comp.lang.ada
 help / color / mirror / Atom feed
From: "David C. Hoos, Sr." <david.c.hoos.sr@ada95.com>
Subject: Re: Serial Port Programming ??
Date: 1999/02/08
Date: 1999-02-08T00:00:00+00:00	[thread overview]
Message-ID: <79nhhi$ne1@hobbes.crc.com> (raw)
In-Reply-To: 36BC2987.322E2423@hei.fr

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 11085 bytes --]


Fr�d�ric Besson wrote in message <36BC2987.322E2423@hei.fr>...
>I 'd like to use my serial port to exchange datas with
>an external card.
>But how can I exchange datas with the serial port with Ada?
>My configuration is: PC under Linux.
>
You didn't give full details, but the solution I provide here works for me with gnat-3.11 (set for native-threads RTS), and RedHat
5.2 (2.0.36).

I had this task on my plate anyway, so when I saw your post, I decided to do it now, rather than later.
This is far from being a finished work, but does demonstrate how it's done in Ada.

First, you need to get the florist library which is an Ada95 binding to POSIX, in accordance with the IEEE spec.  The library is
available at http://www.cs.fsu.edu/~baker/ftp/pub/PART/FLORIST/
in the file "florist981211.tar.gz"

I had to apply the following patch to get the library to build:

---- begin patch ----
diff -Naur orig/florist-3.12w/posix-implementation.gpb new/florist-3.12w/posix-implementation.gpb
--- orig/florist-3.12w/posix-implementation.gpb Sat Sep 19 07:51:22 1998
+++ new/florist-3.12w/posix-implementation.gpb Mon Feb  8 13:24:56 1999
@@ -436,7 +436,9 @@
    end To_Struct_Timeval;

 #if HAVE_Leroy_Threads then
+   function getpid return pid_t;
+   pragma Import (C, getpid, getpid_LINKNAME);
 begin
-   This_Process := Process_ID (getpid);
+   This_Process := getpid;
 #end if;
 end POSIX.Implementation;
diff -Naur orig/florist-3.12w/posix-unsafe_process_primitives.gpb new/florist-3.12w/posix-unsafe_process_primitives.gpb
--- orig/florist-3.12w/posix-unsafe_process_primitives.gpb Sat Sep 19 07:51:33 1998
+++ new/florist-3.12w/posix-unsafe_process_primitives.gpb Mon Feb  8 13:24:56 1999
@@ -105,9 +105,9 @@
       Result := fork;
       if Result = -1 then Raise_POSIX_Error; end if;
       if Result = 0 then
-#        if HAVE_Leroy_Threads then
-         This_Process := getpid;
-#        end if;
+--  #        if HAVE_Leroy_Threads then
+--          This_Process := getpid;
+--  #        end if;
          --  reset soft links to non-tasking versions of operations
 #        if HAVE_Soft_Abort_Defer
          TSL.Abort_Defer        := TSL.Abort_Defer_NT'Access;
--- end patch ---

Then I wrote a small test program which just sends "ATZ" to a modem, and waits for a response, and displays it, then sends "ATI7",
waits for the response, and displays it.

Here is the Ada95 source code for that test program:

---- begin Ada source code ----
with Ada.Calendar;
with Ada.Characters.Latin_1;
with Ada.Command_Line;
with Ada.Exceptions;
with Ada.Strings.Unbounded;
with Ada.Text_IO;
with Interfaces.C;
with POSIX.C;
with POSIX.IO;
with POSIX.Terminal_Functions;
with System;
procedure Serial is

   -- NOTE:  This is far from complete.  Most of this should be in a separate
   -- package, done to a higher level of abstraction, and implementation details
   -- should be hidden.
   -- This is just "quick and dirty" for proof of concept.

   subtype File_Descriptor is POSIX.IO.File_Descriptor;
   use type File_Descriptor;

   subtype Bit_Rate is POSIX.Terminal_Functions.Baud_Rate;

   Serial_File_Descriptor : File_Descriptor;
   Characteristics        : POSIX.Terminal_functions.Terminal_Characteristics;
   Invalid_Command_Line       : exception;
   Unable_To_Open_Serial_Port : exception;
   Invalid_Bit_Rate           : exception;

   use type POSIX.POSIX_String;
   CR : constant POSIX.POSIX_Character := POSIX.POSIX_Character'Val (13);
   LF : constant POSIX.POSIX_Character := POSIX.POSIX_Character'Val (10);
   Modem_Reset : constant POSIX.POSIX_String := "ATZ" & CR;
   Modem_Query : constant POSIX.POSIX_String := "ATI7" & CR;
   Modem_Response     : POSIX.POSIX_String (1 .. 20480);
   Modem_Read_Length  : POSIX.IO_Count;
   Modem_Write_Length : POSIX.IO_Count;
   Rate               : Bit_Rate;
   Modes              : POSIX.Terminal_Functions.Terminal_Modes_Set;
   use type POSIX.IO.Open_Option_Set;
   function Image
     (Modes : POSIX.Terminal_Functions.Terminal_Modes_Set)
      return POSIX.POSIX_String is
      Result : Ada.Strings.Unbounded.Unbounded_String :=
        Ada.Strings.Unbounded.Null_Unbounded_String;
   begin
      for M in Modes'Range loop
         declare
            Modes_Image : constant String :=
              POSIX.Terminal_Functions.Terminal_Modes'Image (M);
            Spacer : constant String
              ( 1 .. (POSIX.Terminal_Functions.Terminal_Modes'Width -
                      Modes_Image'Length) + 1) := (others => ' ');
            begin
               Ada.Strings.Unbounded.Append
                 (Source => Result,
                  New_Item => Modes_Image &
                  Spacer & Boolean'Image
                  (Modes (M)) & Ada.Characters.Latin_1.LF);
            end;
      end loop;
      return POSIX.To_POSIX_String (Ada.Strings.Unbounded.To_String (Result));
   end Image;

   procedure Read
   (FD      :     File_Descriptor;
    Item    : out POSIX.POSIX_String;
    Timeout :     Duration;
    Last    : out POSIX.IO_Count)
   is
      use type  POSIX.IO_Count;
   begin
      Last := POSIX.IO_Count (Item'First - 1);
      -- Since the POSIX.IO.Read command will return whenever it reads a
      -- CR character in the stream, we keep reading until there is a
      -- period of Timeout seconds with no more input, then aborts the
      -- blocking POSIX.IO>Read, and returns with the data.
      -- This procedure is not robust in such areas as buffer overflow.
      loop
         select
            delay Timeout;
            exit;
         then abort
           POSIX.IO.Read
             (File   => FD,
              Buffer => Item (Natural (Last) + 1 .. Item'Last),
              Last   => Last);
         end select;
      end loop;
   end Read;

begin
   if Ada.Command_Line.Argument_Count /= 3 then
      Ada.Exceptions.Raise_Exception
        (E => Invalid_Command_Line'Identity,
         Message =>
           "USAGE: " &
         Ada.Command_Line.Command_Name &
         " <device-name> <time-to-wait> (sec.) <bit-rate> (bps)");
   end if;
   declare
      Device_Name : constant POSIX.Pathname :=
        POSIX.To_POSIX_String (Ada.Command_Line.Argument (1));
      Time_To_Wait : constant Duration :=
        Duration'Value (Ada.Command_Line.Argument (2));
   begin
      begin
         Rate := Bit_Rate'Value ("B" & Ada.Command_Line.Argument (3));
      exception
         when Constraint_Error =>
            Ada.Exceptions.Raise_Exception
              (E => Invalid_Bit_Rate'Identity,
               Message =>
                 "Attempted setting => """ &
               Ada.Command_Line.Argument (3) & """");
      end;
      select
      -- We add one second here, so as to give time for the open operation.
      delay Time_To_Wait + 1.0;
      Ada.Exceptions.Raise_Exception
        (E => Unable_To_Open_Serial_Port'Identity,
         Message => "Operation timed out");
   then abort
     Ada.Text_IO.Put_Line
     (POSIX.To_String
      ("Attempting to open """ &
       Device_Name &
       """ for input and output..."));
   Serial_File_Descriptor := POSIX.IO.Open
     (Name    => Device_Name,
      Mode    => POSIX.IO.Read_Write,
      Options =>
        POSIX.IO.Not_Controlling_Terminal
      - POSIX.IO.Non_Blocking);
      end select;
   exception
      when E: others =>
         Ada.Exceptions.Raise_Exception
           (E => Ada.Exceptions.Exception_Identity (E),
            Message => Ada.Exceptions.Exception_Information (E) &
            POSIX.To_String
            ("while attempting to open file """ &
             Device_Name &
             """ for input"));
   end;
   -- If we get here, the file is open.
   Characteristics := POSIX.Terminal_Functions.Get_Terminal_Characteristics
     (File => Serial_File_Descriptor);
   Modes := POSIX.Terminal_Functions.Terminal_Modes_Of
     (Characteristics => Characteristics);
   Ada.Text_IO.Put_Line
     ("Initial modes:" & Ada.Characters.Latin_1.Lf &
      POSIX.To_String (Image (Modes)));
   POSIX.Terminal_Functions.Define_Output_Baud_Rate
     (Characteristics  => Characteristics,
      Output_Baud_Rate => Rate);

   POSIX.Terminal_Functions.Define_Input_Baud_Rate
     (Characteristics => Characteristics,
      Input_Baud_Rate => Rate);

   Modes (POSIX.Terminal_Functions.Canonical_Input) := False;
   Modes (POSIX.Terminal_Functions.Map_Cr_To_Lf) := False;
   Modes (POSIX.Terminal_Functions.Echo) := False;

   POSIX.Terminal_Functions.Define_Terminal_Modes
     (Characteristics => Characteristics,
      Modes           => Modes);

   POSIX.Terminal_Functions.Define_Input_Time
     (Characteristics => Characteristics,
      Input_Time      => 1.0);

   POSIX.Terminal_Functions.Define_Minimum_Input_Count
     (Characteristics     => Characteristics,
      Minimum_Input_Count => 0);

   POSIX.Terminal_Functions.Set_Terminal_Characteristics
     (File            => Serial_File_Descriptor,
      Characteristics => Characteristics,
      Masked_Signals  => POSIX.All_Signals);

   Modes := POSIX.Terminal_Functions.Terminal_Modes_Of
     (Characteristics => Characteristics);
   Ada.Text_IO.Put_Line
     ("Operating modes:" & Ada.Characters.Latin_1.Lf &
      POSIX.To_String (Image (Modes)));

   delay 0.1;

   POSIX.IO.Write
     (File   => Serial_File_Descriptor,
      Buffer => Modem_Reset,
      Last   => Modem_Write_Length);

   Ada.Text_IO.Put_Line ("Sent:");
   Ada.Text_IO.Put_Line
     (POSIX.To_String
      (Modem_Reset
       (Modem_Reset'First ..
        Modem_Reset'First + Natural (Modem_Write_Length) - 1)));
   Read
     (FD      => Serial_File_Descriptor,
      Item    => Modem_Response,
      Last    => Modem_Read_Length,
      -- Alloww 0.1 sec. + 100 bit times
      Timeout => 0.1 + 100.0 / Natural'Value (Ada.Command_Line.Argument (3)));
   Ada.Text_IO.Put_Line
     (POSIX.To_string
      ("Received: """ & Modem_Response
       (Modem_Response'First ..
        Modem_Response'First + Natural (Modem_Read_Length) - 1) &
      """"));

   POSIX.IO.Write
     (File   => Serial_File_Descriptor,
      Buffer => Modem_Query,
      Last   => Modem_Write_Length);

   Ada.Text_IO.Put_Line ("Sent:");
   Ada.Text_IO.Put_Line
     (POSIX.To_String
      (Modem_Query
       (Modem_Query'First ..
        Modem_Query'First + Natural (Modem_Write_Length) - 1)));
   Read
     (FD      => Serial_File_Descriptor,
      item    => Modem_Response,
      Last    => Modem_Read_Length,
      -- Alloww 0.1 sec. + 100 bit times
      Timeout => 0.1 + 100.0 / Natural'Value (Ada.Command_Line.Argument (3)));
   Ada.Text_IO.Put_Line
     (POSIX.To_string
      ("Received: """ & Modem_Response
       (Modem_Response'First ..
        Modem_Response'First + Natural (Modem_Read_Length) - 1) &
      """"));

exception
   when E: others =>
      Ada.Text_IO.Put_Line
        (Ada.Exceptions.Exception_Information (E));
      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
end Serial;

--- end Ada source code ---

The device name to use is the appropriate ones of /dev/ttyS0 (for COM1:) through /dev/ttySn (for COMn+1:)

Hope this helps.

David C. Hoos, Sr.







  parent reply	other threads:[~1999-02-08  0:00 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-02-06  0:00 Serial Port Programming ?? Fr�d�ric Besson
1999-02-06  0:00 ` Thomas Handler
1999-02-08  0:00 ` David C. Hoos, Sr. [this message]
1999-02-09  0:00   ` Fr�d�ric BESSON
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox