Commit 55d4e2ba by Dmitriy Anisimkov Committed by Pierre-Marie de Rodat

[Ada] GNAT.Serial_Communications: simplify the Serial_Port structure

2019-07-08  Dmitriy Anisimkov  <anisimko@adacore.com>

gcc/ada/

	* libgnat/g-sercom.ads
	(Serial_Port_Descriptor): New type.
	(Serial_Port): Add a comment, make it hold a
	Serial_Port_Descriptor.
	(To_Ada, To_C): New procedures.
	(Port_Data, Port_Data_Access): Remove types.
	* libgnat/g-sercom.adb (To_Ada): New stub.
	* libgnat/g-sercom__linux.adb, libgnat/g-sercom__mingw.adb:
	Update implementations accordingly.
	* s-oscons-tmplt.c: Bind Serial_Port_Descriptor to
	System.Win32.HANDLE on Windows, and to Interfaces.C.int on
	Linux. Add "Interfaces.C." prefix for other basic integer type
	bindings.
	* xoscons.adb (Output_Info): Remove the "Interfaces.C." prefix
	for subtypes generation.

From-SVN: r273225
parent aec80f20
2019-07-08 Dmitriy Anisimkov <anisimko@adacore.com>
* libgnat/g-sercom.ads
(Serial_Port_Descriptor): New type.
(Serial_Port): Add a comment, make it hold a
Serial_Port_Descriptor.
(To_Ada, To_C): New procedures.
(Port_Data, Port_Data_Access): Remove types.
* libgnat/g-sercom.adb (To_Ada): New stub.
* libgnat/g-sercom__linux.adb, libgnat/g-sercom__mingw.adb:
Update implementations accordingly.
* s-oscons-tmplt.c: Bind Serial_Port_Descriptor to
System.Win32.HANDLE on Windows, and to Interfaces.C.int on
Linux. Add "Interfaces.C." prefix for other basic integer type
bindings.
* xoscons.adb (Output_Info): Remove the "Interfaces.C." prefix
for subtypes generation.
2019-07-08 Arnaud Charlet <charlet@adacore.com> 2019-07-08 Arnaud Charlet <charlet@adacore.com>
* doc/gnat_rm/standard_and_implementation_defined_restrictions.rst: * doc/gnat_rm/standard_and_implementation_defined_restrictions.rst:
......
...@@ -103,6 +103,15 @@ package body GNAT.Serial_Communications is ...@@ -103,6 +103,15 @@ package body GNAT.Serial_Communications is
Unimplemented; Unimplemented;
end Read; end Read;
------------
-- To_Ada --
------------
procedure To_Ada (Port : out Serial_Port; Fd : Serial_Port_Descriptor) is
begin
Unimplemented;
end To_Ada;
----------- -----------
-- Write -- -- Write --
----------- -----------
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
with Ada.Streams; with Ada.Streams;
with Interfaces.C; with Interfaces.C;
with System.OS_Constants;
package GNAT.Serial_Communications is package GNAT.Serial_Communications is
...@@ -122,6 +123,11 @@ package GNAT.Serial_Communications is ...@@ -122,6 +123,11 @@ package GNAT.Serial_Communications is
-- No flow control, hardware flow control, software flow control -- No flow control, hardware flow control, software flow control
type Serial_Port is new Ada.Streams.Root_Stream_Type with private; type Serial_Port is new Ada.Streams.Root_Stream_Type with private;
-- Serial port stream type
type Serial_Port_Descriptor is
new System.OS_Constants.Serial_Port_Descriptor;
-- OS specific serial port descriptor
procedure Open procedure Open
(Port : out Serial_Port; (Port : out Serial_Port;
...@@ -168,13 +174,21 @@ package GNAT.Serial_Communications is ...@@ -168,13 +174,21 @@ package GNAT.Serial_Communications is
procedure Close (Port : in out Serial_Port); procedure Close (Port : in out Serial_Port);
-- Close port -- Close port
private procedure To_Ada (Port : out Serial_Port; Fd : Serial_Port_Descriptor)
with Inline;
-- Convert a serial port descriptor to Serial_Port. This is useful when a
-- serial port descriptor is obtained from an external library call.
type Port_Data; function To_C
type Port_Data_Access is access Port_Data; (Port : Serial_Port) return Serial_Port_Descriptor with Inline;
-- Return a serial port descriptor to be used by external subprograms.
-- This is useful for C functions that are not yet interfaced in this
-- package.
private
type Serial_Port is new Ada.Streams.Root_Stream_Type with record type Serial_Port is new Ada.Streams.Root_Stream_Type with record
H : Port_Data_Access; H : Serial_Port_Descriptor := -1;
end record; end record;
Data_Rate_Value : constant array (Data_Rate) of Interfaces.C.unsigned := Data_Rate_Value : constant array (Data_Rate) of Interfaces.C.unsigned :=
...@@ -205,4 +219,7 @@ private ...@@ -205,4 +219,7 @@ private
B3500000 => 3_500_000, B3500000 => 3_500_000,
B4000000 => 4_000_000); B4000000 => 4_000_000);
function To_C (Port : Serial_Port) return Serial_Port_Descriptor is
(Port.H);
end GNAT.Serial_Communications; end GNAT.Serial_Communications;
...@@ -33,12 +33,10 @@ ...@@ -33,12 +33,10 @@
with Ada.Streams; use Ada.Streams; with Ada.Streams; use Ada.Streams;
with Ada; use Ada; with Ada; use Ada;
with Ada.Unchecked_Deallocation;
with System; use System; with System; use System;
with System.Communication; use System.Communication; with System.Communication; use System.Communication;
with System.CRTL; use System.CRTL; with System.CRTL; use System.CRTL;
with System.OS_Constants;
with GNAT.OS_Lib; use GNAT.OS_Lib; with GNAT.OS_Lib; use GNAT.OS_Lib;
...@@ -48,8 +46,6 @@ package body GNAT.Serial_Communications is ...@@ -48,8 +46,6 @@ package body GNAT.Serial_Communications is
use type Interfaces.C.unsigned; use type Interfaces.C.unsigned;
type Port_Data is new int;
subtype unsigned is Interfaces.C.unsigned; subtype unsigned is Interfaces.C.unsigned;
subtype char is Interfaces.C.char; subtype char is Interfaces.C.char;
subtype unsigned_char is Interfaces.C.unsigned_char; subtype unsigned_char is Interfaces.C.unsigned_char;
...@@ -124,20 +120,16 @@ package body GNAT.Serial_Communications is ...@@ -124,20 +120,16 @@ package body GNAT.Serial_Communications is
Res : int; Res : int;
begin begin
if Port.H = null then Port.H := Serial_Port_Descriptor (open
Port.H := new Port_Data;
end if;
Port.H.all := Port_Data (open
(C_Name (C_Name'First)'Address, int (O_RDWR + O_NOCTTY + O_NDELAY))); (C_Name (C_Name'First)'Address, int (O_RDWR + O_NOCTTY + O_NDELAY)));
if Port.H.all = -1 then if Port.H = -1 then
Raise_Error ("open: open failed"); Raise_Error ("open: open failed");
end if; end if;
-- By default we are in blocking mode -- By default we are in blocking mode
Res := fcntl (int (Port.H.all), F_SETFL, 0); Res := fcntl (int (Port.H), F_SETFL, 0);
if Res = -1 then if Res = -1 then
Raise_Error ("open: fcntl failed"); Raise_Error ("open: fcntl failed");
...@@ -169,11 +161,11 @@ package body GNAT.Serial_Communications is ...@@ -169,11 +161,11 @@ package body GNAT.Serial_Communications is
Res : ssize_t; Res : ssize_t;
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("read: port not opened", 0); Raise_Error ("read: port not opened", 0);
end if; end if;
Res := read (Integer (Port.H.all), Buffer'Address, Len); Res := read (Integer (Port.H), Buffer'Address, Len);
if Res = -1 then if Res = -1 then
Raise_Error ("read failed"); Raise_Error ("read failed");
...@@ -228,13 +220,13 @@ package body GNAT.Serial_Communications is ...@@ -228,13 +220,13 @@ package body GNAT.Serial_Communications is
-- Warnings off, since we don't always test the result -- Warnings off, since we don't always test the result
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("set: port not opened", 0); Raise_Error ("set: port not opened", 0);
end if; end if;
-- Get current port settings -- Get current port settings
Res := tcgetattr (int (Port.H.all), Current'Address); Res := tcgetattr (int (Port.H), Current'Address);
-- Change settings now -- Change settings now
...@@ -269,18 +261,27 @@ package body GNAT.Serial_Communications is ...@@ -269,18 +261,27 @@ package body GNAT.Serial_Communications is
-- Set port settings -- Set port settings
Res := tcflush (int (Port.H.all), TCIFLUSH); Res := tcflush (int (Port.H), TCIFLUSH);
Res := tcsetattr (int (Port.H.all), TCSANOW, Current'Address); Res := tcsetattr (int (Port.H), TCSANOW, Current'Address);
-- Block -- Block
Res := fcntl (int (Port.H.all), F_SETFL, (if Block then 0 else FNDELAY)); Res := fcntl (int (Port.H), F_SETFL, (if Block then 0 else FNDELAY));
if Res = -1 then if Res = -1 then
Raise_Error ("set: fcntl failed"); Raise_Error ("set: fcntl failed");
end if; end if;
end Set; end Set;
------------
-- To_Ada --
------------
procedure To_Ada (Port : out Serial_Port; Fd : Serial_Port_Descriptor) is
begin
Port.H := Fd;
end To_Ada;
----------- -----------
-- Write -- -- Write --
----------- -----------
...@@ -293,11 +294,11 @@ package body GNAT.Serial_Communications is ...@@ -293,11 +294,11 @@ package body GNAT.Serial_Communications is
Res : ssize_t; Res : ssize_t;
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("write: port not opened", 0); Raise_Error ("write: port not opened", 0);
end if; end if;
Res := write (int (Port.H.all), Buffer'Address, Len); Res := write (int (Port.H), Buffer'Address, Len);
if Res = -1 then if Res = -1 then
Raise_Error ("write failed"); Raise_Error ("write failed");
...@@ -311,16 +312,12 @@ package body GNAT.Serial_Communications is ...@@ -311,16 +312,12 @@ package body GNAT.Serial_Communications is
----------- -----------
procedure Close (Port : in out Serial_Port) is procedure Close (Port : in out Serial_Port) is
procedure Unchecked_Free is
new Unchecked_Deallocation (Port_Data, Port_Data_Access);
Res : int; Res : int;
pragma Unreferenced (Res); pragma Unreferenced (Res);
begin begin
if Port.H /= null then if Port.H /= -1 then
Res := close (int (Port.H.all)); Res := close (int (Port.H));
Unchecked_Free (Port.H);
end if; end if;
end Close; end Close;
......
...@@ -31,13 +31,11 @@ ...@@ -31,13 +31,11 @@
-- This is the Windows implementation of this package -- This is the Windows implementation of this package
with Ada.Streams; use Ada.Streams; with Ada.Streams; use Ada.Streams, Ada;
with Ada.Unchecked_Deallocation; use Ada;
with System; use System; with System; use System;
with System.Communication; use System.Communication; with System.Communication; use System.Communication;
with System.CRTL; use System.CRTL; with System.CRTL; use System.CRTL;
with System.OS_Constants;
with System.Win32; use System.Win32; with System.Win32; use System.Win32;
with System.Win32.Ext; use System.Win32.Ext; with System.Win32.Ext; use System.Win32.Ext;
...@@ -49,8 +47,6 @@ package body GNAT.Serial_Communications is ...@@ -49,8 +47,6 @@ package body GNAT.Serial_Communications is
-- Common types -- Common types
type Port_Data is new HANDLE;
C_Bits : constant array (Data_Bits) of Interfaces.C.unsigned := (8, 7); C_Bits : constant array (Data_Bits) of Interfaces.C.unsigned := (8, 7);
C_Parity : constant array (Parity_Check) of Interfaces.C.unsigned := C_Parity : constant array (Parity_Check) of Interfaces.C.unsigned :=
(None => NOPARITY, Odd => ODDPARITY, Even => EVENPARITY); (None => NOPARITY, Odd => ODDPARITY, Even => EVENPARITY);
...@@ -69,15 +65,11 @@ package body GNAT.Serial_Communications is ...@@ -69,15 +65,11 @@ package body GNAT.Serial_Communications is
----------- -----------
procedure Close (Port : in out Serial_Port) is procedure Close (Port : in out Serial_Port) is
procedure Unchecked_Free is
new Unchecked_Deallocation (Port_Data, Port_Data_Access);
Success : BOOL; Success : BOOL;
begin begin
if Port.H /= null then if Port.H /= -1 then
Success := CloseHandle (HANDLE (Port.H.all)); Success := CloseHandle (HANDLE (Port.H));
Unchecked_Free (Port.H);
if Success = Win32.FALSE then if Success = Win32.FALSE then
Raise_Error ("error closing the port"); Raise_Error ("error closing the port");
...@@ -114,13 +106,11 @@ package body GNAT.Serial_Communications is ...@@ -114,13 +106,11 @@ package body GNAT.Serial_Communications is
pragma Unreferenced (Success); pragma Unreferenced (Success);
begin begin
if Port.H = null then if Port.H /= -1 then
Port.H := new Port_Data; Success := CloseHandle (HANDLE (Port.H));
else
Success := CloseHandle (HANDLE (Port.H.all));
end if; end if;
Port.H.all := CreateFileA Port.H := CreateFileA
(lpFileName => C_Name (C_Name'First)'Address, (lpFileName => C_Name (C_Name'First)'Address,
dwDesiredAccess => GENERIC_READ or GENERIC_WRITE, dwDesiredAccess => GENERIC_READ or GENERIC_WRITE,
dwShareMode => 0, dwShareMode => 0,
...@@ -129,7 +119,9 @@ package body GNAT.Serial_Communications is ...@@ -129,7 +119,9 @@ package body GNAT.Serial_Communications is
dwFlagsAndAttributes => 0, dwFlagsAndAttributes => 0,
hTemplateFile => 0); hTemplateFile => 0);
if Port.H.all = Port_Data (INVALID_HANDLE_VALUE) then pragma Assert (INVALID_HANDLE_VALUE = -1);
if Port.H = Serial_Port_Descriptor (INVALID_HANDLE_VALUE) then
Raise_Error ("cannot open com port"); Raise_Error ("cannot open com port");
end if; end if;
end Open; end Open;
...@@ -159,13 +151,13 @@ package body GNAT.Serial_Communications is ...@@ -159,13 +151,13 @@ package body GNAT.Serial_Communications is
Read_Last : aliased DWORD; Read_Last : aliased DWORD;
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("read: port not opened", 0); Raise_Error ("read: port not opened", 0);
end if; end if;
Success := Success :=
ReadFile ReadFile
(hFile => HANDLE (Port.H.all), (hFile => HANDLE (Port.H),
lpBuffer => Buffer (Buffer'First)'Address, lpBuffer => Buffer (Buffer'First)'Address,
nNumberOfBytesToRead => DWORD (Buffer'Length), nNumberOfBytesToRead => DWORD (Buffer'Length),
lpNumberOfBytesRead => Read_Last'Access, lpNumberOfBytesRead => Read_Last'Access,
...@@ -200,15 +192,14 @@ package body GNAT.Serial_Communications is ...@@ -200,15 +192,14 @@ package body GNAT.Serial_Communications is
Com_Settings : aliased DCB; Com_Settings : aliased DCB;
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("set: port not opened", 0); Raise_Error ("set: port not opened", 0);
end if; end if;
Success := GetCommState (HANDLE (Port.H.all), Com_Settings'Access); Success := GetCommState (HANDLE (Port.H), Com_Settings'Access);
if Success = Win32.FALSE then if Success = Win32.FALSE then
Success := CloseHandle (HANDLE (Port.H.all)); Success := CloseHandle (HANDLE (Port.H));
Port.H.all := 0;
Raise_Error ("set: cannot get comm state"); Raise_Error ("set: cannot get comm state");
end if; end if;
...@@ -240,11 +231,10 @@ package body GNAT.Serial_Communications is ...@@ -240,11 +231,10 @@ package body GNAT.Serial_Communications is
Com_Settings.Parity := BYTE (C_Parity (Parity)); Com_Settings.Parity := BYTE (C_Parity (Parity));
Com_Settings.StopBits := BYTE (C_Stop_Bits (Stop_Bits)); Com_Settings.StopBits := BYTE (C_Stop_Bits (Stop_Bits));
Success := SetCommState (HANDLE (Port.H.all), Com_Settings'Access); Success := SetCommState (HANDLE (Port.H), Com_Settings'Access);
if Success = Win32.FALSE then if Success = Win32.FALSE then
Success := CloseHandle (HANDLE (Port.H.all)); Success := CloseHandle (HANDLE (Port.H));
Port.H.all := 0;
Raise_Error ("cannot set comm state"); Raise_Error ("cannot set comm state");
end if; end if;
...@@ -274,7 +264,7 @@ package body GNAT.Serial_Communications is ...@@ -274,7 +264,7 @@ package body GNAT.Serial_Communications is
Success := Success :=
SetCommTimeouts SetCommTimeouts
(hFile => HANDLE (Port.H.all), (hFile => HANDLE (Port.H),
lpCommTimeouts => Com_Time_Out'Access); lpCommTimeouts => Com_Time_Out'Access);
if Success = Win32.FALSE then if Success = Win32.FALSE then
...@@ -282,6 +272,15 @@ package body GNAT.Serial_Communications is ...@@ -282,6 +272,15 @@ package body GNAT.Serial_Communications is
end if; end if;
end Set; end Set;
------------
-- To_Ada --
------------
procedure To_Ada (Port : out Serial_Port; Fd : Serial_Port_Descriptor) is
begin
Port.H := Fd;
end To_Ada;
----------- -----------
-- Write -- -- Write --
----------- -----------
...@@ -294,13 +293,13 @@ package body GNAT.Serial_Communications is ...@@ -294,13 +293,13 @@ package body GNAT.Serial_Communications is
Temp_Last : aliased DWORD; Temp_Last : aliased DWORD;
begin begin
if Port.H = null then if Port.H = -1 then
Raise_Error ("write: port not opened", 0); Raise_Error ("write: port not opened", 0);
end if; end if;
Success := Success :=
WriteFile WriteFile
(hFile => HANDLE (Port.H.all), (hFile => HANDLE (Port.H),
lpBuffer => Buffer'Address, lpBuffer => Buffer'Address,
nNumberOfBytesToWrite => DWORD (Buffer'Length), nNumberOfBytesToWrite => DWORD (Buffer'Length),
lpNumberOfBytesWritten => Temp_Last'Access, lpNumberOfBytesWritten => Temp_Last'Access,
......
...@@ -261,6 +261,14 @@ main (void) { ...@@ -261,6 +261,14 @@ main (void) {
TXT("-- This is the version for " TARGET) TXT("-- This is the version for " TARGET)
TXT("") TXT("")
TXT("with Interfaces.C;") TXT("with Interfaces.C;")
#if defined (__MINGW32__)
# define TARGET_OS "Windows"
# define Serial_Port_Descriptor "System.Win32.HANDLE"
TXT("with System.Win32;")
#else
# define TARGET_OS "Other_OS"
# define Serial_Port_Descriptor "Interfaces.C.int"
#endif
/* /*
package System.OS_Constants is package System.OS_Constants is
...@@ -280,11 +288,6 @@ package System.OS_Constants is ...@@ -280,11 +288,6 @@ package System.OS_Constants is
type OS_Type is (Windows, Other_OS); type OS_Type is (Windows, Other_OS);
*/ */
#if defined (__MINGW32__)
# define TARGET_OS "Windows"
#else
# define TARGET_OS "Other_OS"
#endif
C("Target_OS", OS_Type, TARGET_OS, "") C("Target_OS", OS_Type, TARGET_OS, "")
/* /*
pragma Warnings (Off, Target_OS); pragma Warnings (Off, Target_OS);
...@@ -303,6 +306,8 @@ CST(Target_Name, "") ...@@ -303,6 +306,8 @@ CST(Target_Name, "")
#define SIZEOF_unsigned_int sizeof (unsigned int) #define SIZEOF_unsigned_int sizeof (unsigned int)
CND(SIZEOF_unsigned_int, "Size of unsigned int") CND(SIZEOF_unsigned_int, "Size of unsigned int")
SUB(Serial_Port_Descriptor)
/* /*
------------------- -------------------
...@@ -405,10 +410,10 @@ CND(FNDELAY, "Nonblocking") ...@@ -405,10 +410,10 @@ CND(FNDELAY, "Nonblocking")
#if defined (__FreeBSD__) || defined (__DragonFly__) #if defined (__FreeBSD__) || defined (__DragonFly__)
# define CNI CNU # define CNI CNU
# define IOCTL_Req_T "unsigned" # define IOCTL_Req_T "Interfaces.C.unsigned"
#else #else
# define CNI CND # define CNI CND
# define IOCTL_Req_T "int" # define IOCTL_Req_T "Interfaces.C.int"
#endif #endif
SUB(IOCTL_Req_T) SUB(IOCTL_Req_T)
...@@ -1628,9 +1633,9 @@ CND(IF_NAMESIZE, "Max size of interface name with 0 terminator"); ...@@ -1628,9 +1633,9 @@ CND(IF_NAMESIZE, "Max size of interface name with 0 terminator");
*/ */
#if defined (__sun__) || defined (__hpux__) #if defined (__sun__) || defined (__hpux__)
# define Msg_Iovlen_T "int" # define Msg_Iovlen_T "Interfaces.C.int"
#else #else
# define Msg_Iovlen_T "size_t" # define Msg_Iovlen_T "Interfaces.C.size_t"
#endif #endif
SUB(Msg_Iovlen_T) SUB(Msg_Iovlen_T)
......
...@@ -229,8 +229,7 @@ procedure XOSCons is ...@@ -229,8 +229,7 @@ procedure XOSCons is
case Lang is case Lang is
when Lang_Ada => when Lang_Ada =>
Put (" subtype " & Info.Constant_Name.all Put (" subtype " & Info.Constant_Name.all
& " is Interfaces.C." & " is " & Info.Text_Value.all & ";");
& Info.Text_Value.all & ";");
when Lang_C => when Lang_C =>
Put ("#define " & Info.Constant_Name.all & " " Put ("#define " & Info.Constant_Name.all & " "
& Info.Text_Value.all); & Info.Text_Value.all);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment