OSDN Git Service

2009-12-01 Ed Schonberg <schonberg@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-sercom-mingw.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
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            --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --                    Copyright (C) 2007-2009, AdaCore                      --
10 --                                                                          --
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.                                              --
21 --                                                                          --
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.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 --  This is the Windows implementation of this package
35
36 with Ada.Unchecked_Deallocation; use Ada;
37 with Ada.Streams;                use Ada.Streams;
38
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;
44
45 package body GNAT.Serial_Communications is
46
47    --  Common types
48
49    type Port_Data is new HANDLE;
50
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);
56
57    -----------
58    -- Files --
59    -----------
60
61    procedure Raise_Error (Message : String; Error : DWORD := GetLastError);
62    pragma No_Return (Raise_Error);
63
64    -----------
65    -- Close --
66    -----------
67
68    procedure Close (Port : in out Serial_Port) is
69       procedure Unchecked_Free is
70         new Unchecked_Deallocation (Port_Data, Port_Data_Access);
71
72       Success : BOOL;
73
74    begin
75       if Port.H /= null then
76          Success := CloseHandle (HANDLE (Port.H.all));
77          Unchecked_Free (Port.H);
78
79          if Success = Win32.FALSE then
80             Raise_Error ("error closing the port");
81          end if;
82       end if;
83    end Close;
84
85    ----------
86    -- Name --
87    ----------
88
89    function Name (Number : Positive) return Port_Name is
90       N_Img : constant String := Positive'Image (Number);
91    begin
92       return Port_Name ("COM" & N_Img (N_Img'First + 1 .. N_Img'Last) & ':');
93    end Name;
94
95    ----------
96    -- Open --
97    ----------
98
99    procedure Open
100      (Port : out Serial_Port;
101       Name : Port_Name)
102    is
103       C_Name  : constant String := String (Name) & ASCII.NUL;
104       Success : BOOL;
105       pragma Unreferenced (Success);
106
107    begin
108       if Port.H = null then
109          Port.H := new Port_Data;
110       else
111          Success := CloseHandle (HANDLE (Port.H.all));
112       end if;
113
114       Port.H.all := CreateFileA
115         (lpFileName            => C_Name (C_Name'First)'Address,
116          dwDesiredAccess       => GENERIC_READ or GENERIC_WRITE,
117          dwShareMode           => 0,
118          lpSecurityAttributes  => null,
119          dwCreationDisposition => OPEN_EXISTING,
120          dwFlagsAndAttributes  => 0,
121          hTemplateFile         => 0);
122
123       if Port.H.all = 0 then
124          Raise_Error ("cannot open com port");
125       end if;
126    end Open;
127
128    -----------------
129    -- Raise_Error --
130    -----------------
131
132    procedure Raise_Error (Message : String; Error : DWORD := GetLastError) is
133    begin
134       raise Serial_Error with Message & " (" & DWORD'Image (Error) & ')';
135    end Raise_Error;
136
137    ----------
138    -- Read --
139    ----------
140
141    overriding procedure Read
142      (Port   : in out Serial_Port;
143       Buffer : out Stream_Element_Array;
144       Last   : out Stream_Element_Offset)
145    is
146       Success   : BOOL;
147       Read_Last : aliased DWORD;
148
149    begin
150       if Port.H = null then
151          Raise_Error ("read: port not opened", 0);
152       end if;
153
154       Success :=
155         ReadFile
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);
161
162       if Success = Win32.FALSE then
163          Raise_Error ("read error");
164       end if;
165
166       Last := Last_Index (Buffer'First, size_t (Read_Last));
167    end Read;
168
169    ---------
170    -- Set --
171    ---------
172
173    procedure Set
174      (Port      : Serial_Port;
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)
181    is
182       Success      : BOOL;
183       Com_Time_Out : aliased COMMTIMEOUTS;
184       Com_Settings : aliased DCB;
185
186    begin
187       if Port.H = null then
188          Raise_Error ("set: port not opened", 0);
189       end if;
190
191       Success := GetCommState (HANDLE (Port.H.all), Com_Settings'Access);
192
193       if Success = Win32.FALSE then
194          Success := CloseHandle (HANDLE (Port.H.all));
195          Port.H.all := 0;
196          Raise_Error ("set: cannot get comm state");
197       end if;
198
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));
213
214       Success := SetCommState (HANDLE (Port.H.all), Com_Settings'Access);
215
216       if Success = Win32.FALSE then
217          Success := CloseHandle (HANDLE (Port.H.all));
218          Port.H.all := 0;
219          Raise_Error ("cannot set comm state");
220       end if;
221
222       --  Set the timeout status
223
224       if Block then
225          Com_Time_Out := (others => 0);
226       else
227          Com_Time_Out :=
228            (ReadTotalTimeoutConstant => DWORD (1000 * Timeout),
229             others                   => 0);
230       end if;
231
232       Success :=
233         SetCommTimeouts
234           (hFile          => HANDLE (Port.H.all),
235            lpCommTimeouts => Com_Time_Out'Access);
236
237       if Success = Win32.FALSE then
238          Raise_Error ("cannot set the timeout");
239       end if;
240    end Set;
241
242    -----------
243    -- Write --
244    -----------
245
246    overriding procedure Write
247      (Port   : in out Serial_Port;
248       Buffer : Stream_Element_Array)
249    is
250       Success   : BOOL;
251       Temp_Last : aliased DWORD;
252
253    begin
254       if Port.H = null then
255          Raise_Error ("write: port not opened", 0);
256       end if;
257
258       Success :=
259         WriteFile
260           (hFile                  => HANDLE (Port.H.all),
261            lpBuffer               => Buffer'Address,
262            nNumberOfBytesToWrite  => DWORD (Buffer'Length),
263            lpNumberOfBytesWritten => Temp_Last'Access,
264            lpOverlapped           => null);
265
266       if Success = Win32.FALSE
267         or else Stream_Element_Offset (Temp_Last) /= Buffer'Length
268       then
269          Raise_Error ("failed to write data");
270       end if;
271    end Write;
272
273 end GNAT.Serial_Communications;