Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/shared/serial_ports/host_app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This host application is for use specifically with the streaming Serial_Port demonstration main program running on the target board. This host app is required so that the string bounds are handled correctly.

The other demonstration mains do not use streams. For those, use a host app such as TerraTerm or RealTerm.
114 changes: 97 additions & 17 deletions examples/shared/serial_ports/host_app/host.adb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2016, AdaCore --
-- Copyright (C) 2016-2025, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
Expand Down Expand Up @@ -30,37 +30,117 @@
------------------------------------------------------------------------------

-- This file contains the source code for an interactive program to be run on
-- a host computer, to communicate via serial port with a program running on
-- a target board. It uses streams to send and receive strings to/from the
-- target board program.
-- a host computer. It communicates via a host serial port with the streaming
-- demonstration program running on a target board. It uses streams to send
-- and receive strings to/from the target board program for the sake of
-- compatible handling of the bounds. This host program is only intended
-- for the streaming demonstration, not for the other target demonstration
-- programs.

-- The program can be connected to the target board with a serial cable that
-- presents a serial port to the host operating system. The "README.md" file
-- associated with this project describes such a cable.
-- This program is to be built with a native machine compiler, not a
-- cross-compiler. The program is known to work on Windows and should work
-- on Linux as well, according to the comments in package GNAT.Communications.

-- You can change the COM port number, or even get it from the command line
-- as an argument, but it must match what the host OS sees from the USB-COM
-- cable. This program has been run successfully on Windows 7 but should run
-- on Linux as well.
-- The host program requires a serial port to communicate with the serial port
-- on the target board, so a cable is required. One way to do that is to use
-- a special cable that makes a host USB port function like a serial port. The
-- "README.md" file associated with this project describes such a cable, which
-- was used in testing.

-- When running it, enter a string at the prompt (">") or just hit carriage
-- On the command line invocation you must specify the host serial port number
-- as an integer number (in any base if you use Ada syntax). That number must
-- correspond to the host serial port connected to the target board. No other
-- command line parameters are accepted.

-- During execution, enter a string at the prompt (">") or just hit carriage
-- return if you are ready to quit. If you do enter a string, it will be sent
-- to the target board, along with the bounds. The program running on the
-- target echos it back so this host app will show that response from the
-- board.
--
-- Note that the baud rate for the host serial port is set below, and although
-- arbitrary, must match the value set by the streaming demo program on the
-- target board. That could be an additional host argument in the future. The
-- target serial port is set to eight data bits, no parity, and one stop bit.
-- Those settings are typically what a host serial port uses for defaults, but
-- not necessarily.

with GNAT.IO; use GNAT.IO;
with GNAT.Serial_Communications; use GNAT.Serial_Communications;
with Ada.Command_Line;

procedure Host is
COM : aliased Serial_Port;
COM3 : constant Port_Name := Name (3);

COM : aliased Serial_Port;
Selected_Port : Integer;
Valid_Selection : Boolean;

Outgoing : String (1 .. 1024); -- arbitrary
Last : Natural;
Last : Natural range Outgoing'First - 1 .. Outgoing'Last;

procedure Get_Port_Number
(Selected_Port : out Integer;
Valid : out Boolean);
-- Get the port number from the command line arguments (only one is
-- expected), ensuring that the argument is a well-formed integer with
-- the required range.
--
-- Note that it does not check whether a valid argument corresponds to an
-- existing host serial port. If it does not, GNAT.Serial_Communications
-- will raise Serial_Error when Open is called.

---------------------
-- Get_Port_Number --
---------------------

procedure Get_Port_Number
(Selected_Port : out Integer;
Valid : out Boolean)
is
use Ada.Command_Line;
begin
Valid := False;
Selected_Port := 0; -- won't be used unless the caller ignores Valid

if Argument_Count /= 1 then
Put_Line ("You must specify (only) the number of the COM port to open on this host.");
Put_Line ("For example, to specify COM3 the invocation would be:");
Put_Line (" host 3");
Put_Line ("The following Windows PowerShell command lists all existing ports:");
Put_Line (" [System.IO.Ports.SerialPort]::GetPortNames()");
return;
end if;

Well_Formed : begin
Selected_Port := Integer'Value (Argument (1));
exception
when others =>
Put_Line ("You must specify a syntactically valid (positive) integer value for the host COM port.");
return;
end Well_Formed;

if Selected_Port < 1 then
Put_Line ("You must specify a positive number for the host COM port.");
-- Because function Name from package GNAT.Serial_Communications
-- requires a positive value.
return;
end if;

Valid := True;
end Get_Port_Number;

begin
COM.Open (COM3);
Get_Port_Number (Selected_Port, Valid_Selection);
if not Valid_Selection then
return;
end if;

COM.Open (Name (Selected_Port));
COM.Set (Rate => B115200, Block => False);
-- The baud rate is arbitrary but must match the selection by the target
-- board's stream demonstration program. The other target serial port
-- settings are N81. That stop bit is likley critical to proper function
-- of the demo.

loop
Put ("> ");
Expand All @@ -74,7 +154,7 @@ begin
declare
Incoming : constant String := String'Input (COM'Access);
begin
Put_Line ("From board: " & Incoming);
Put_Line ("Received from board: " & Incoming);
end;
end loop;

Expand Down
23 changes: 15 additions & 8 deletions examples/shared/serial_ports/src/demo_serial_port_blocking.adb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2015-2022, AdaCore --
-- Copyright (C) 2015-2025, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
Expand Down Expand Up @@ -37,12 +37,10 @@ with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler);
-- an exception is propagated. We need it in the executable, therefore it
-- must be somewhere in the closure of the context clauses.

with Peripherals_Blocking; use Peripherals_Blocking;
with Peripherals_Blocking; use Peripherals_Blocking; -- for COM
with Serial_IO.Blocking; use Serial_IO.Blocking;
with Message_Buffers; use Message_Buffers;

use Serial_IO;

procedure Demo_Serial_Port_Blocking is

Incoming : aliased Message (Physical_Size => 1024); -- arbitrary size
Expand All @@ -53,18 +51,27 @@ procedure Demo_Serial_Port_Blocking is
procedure Send (This : String) is
begin
Set (Outgoing, To => This);
Blocking.Send (COM, Outgoing'Unchecked_Access);
Send (COM, Outgoing'Unchecked_Access);
-- Send won't return until the entire message has been sent
end Send;

begin
Initialize_Hardware (COM);
Configure (COM, Baud_Rate => 115_200);
Serial_IO.Initialize_Hardware (Peripheral);
Serial_IO.Configure (COM.Device, Baud_Rate => 115_200);
-- This baud rate selection is entirely arbitrary. Note that you may have
-- to alter the settings of your host serial port to match this baud rate,
-- or just change the above to match whatever the host serial port has set
-- already. An application such as TerraTerm or RealTerm is helpful.

Incoming.Set_Terminator (To => ASCII.CR);
Send ("Enter text, terminated by CR.");
-- Note that you may have to alter the settings on your host serial port
-- so that the terminator char is not stripped off automatically by the
-- host driver, which may happen especially when CR is the terminator.
-- An application such as TerraTerm or RealTerm is helpful.

loop
Blocking.Receive (COM, Incoming'Unchecked_Access);
Receive (COM, Incoming'Unchecked_Access);
Send ("Received : " & Incoming.Content);
end loop;
end Demo_Serial_Port_Blocking;
44 changes: 26 additions & 18 deletions examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2015-2022, AdaCore --
-- Copyright (C) 2015-2025, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
Expand Down Expand Up @@ -29,9 +29,9 @@
-- --
------------------------------------------------------------------------------

-- A demonstration of a higher-level USART interface, using interrupts to
-- achieve non-blocking I/O (calls to Send and Receive return potentially
-- prior to I/O completion). The file declares the main procedure.
-- A demonstration of a higher-level USART interface, using interrupts
-- to achieve non-blocking I/O (calls to Start_Sending and Receive return
-- potentially prior to I/O completion). The file declares the main procedure.

with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler);
-- The "last chance handler" is the user-defined routine that is called when
Expand All @@ -42,33 +42,41 @@ with Peripherals_Nonblocking; use Peripherals_Nonblocking;
with Serial_IO.Nonblocking; use Serial_IO.Nonblocking;
with Message_Buffers; use Message_Buffers;

use Serial_IO;

procedure Demo_Serial_Port_Nonblocking is

Incoming : aliased Message (Physical_Size => 1024); -- arbitrary size
Outgoing : aliased Message (Physical_Size => 1024); -- arbitrary size

procedure Send (This : String);
procedure Start_Sending (This : String);

procedure Send (This : String) is
procedure Start_Sending (This : String) is
begin
Set (Outgoing, To => This);
Nonblocking.Send (COM, Outgoing'Unchecked_Access);
Await_Transmission_Complete (Outgoing);
-- Send can/will return before the entire message has been sent
end Send;
Send (COM, Outgoing'Unchecked_Access);
Outgoing.Await_Transmission_Complete;
-- We wait anyway, just to keep things simple for the display
end Start_Sending;

begin
Initialize_Hardware (COM);
Configure (COM, Baud_Rate => 115_200);
Serial_IO.Initialize_Hardware (Peripheral);
Serial_IO.Configure (COM.Device, Baud_Rate => 115_200);
-- This baud rate selection is entirely arbitrary. Note that you may have
-- to alter the settings of your host serial port to match this baud rate,
-- or just change the above to match whatever the host serial port has set
-- already. An application such as TerraTerm or RealTerm is helpful.

Incoming.Set_Terminator (To => ASCII.CR);
Send ("Enter text, terminated by CR.");
Start_Sending ("Enter text, terminated by CR.");
-- Note that you may have to alter the settings on your host serial port so
-- that the terminator char is not stripped off automatically by the host
-- driver, which may happen especially when CR is the terminator. You may
-- find that an application such as TerraTerm or RealTerm is helpful.

loop
Nonblocking.Receive (COM, Incoming'Unchecked_Access);
Await_Reception_Complete (Incoming);
Send ("Received : " & Incoming.Content);
Receive (COM, Incoming'Unchecked_Access);
Incoming.Await_Reception_Complete;
-- We wait anyway, just to keep things simple for the display
Start_Sending ("Received : " & Incoming.Content);
end loop;
end Demo_Serial_Port_Nonblocking;

74 changes: 17 additions & 57 deletions examples/shared/serial_ports/src/demo_serial_port_streaming.adb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2016-2022, AdaCore --
-- Copyright (C) 2016-2025, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
Expand Down Expand Up @@ -44,82 +44,42 @@
-- HOST COMPUTER SIDE:

-- The incoming strings are intended to come from another program, presumably
-- running on the host computer, connected to the target board with a
-- serial cable that presents a serial port to the host operating system. The
-- "README.md" file associated with this project describes such a cable. A
-- sample host-side program is described below.
-- running on the host computer, connected to the target board with a cable
-- that presents a serial port to the host operating system. The "README.md"
-- file associated with this project describes such a cable.

-- Note that, because it uses the stream attributes String'Output and
-- String'Input, which write and read the bounds as well as the characters,
-- you will need to use a program on the host that uses streams to send
-- and receive these String values. Here is a sample interactive program,
-- hardcoded arbitrarily to use COM3 on Windows. Note that the source code for
-- this program is included in the root of this project, not in the source dir
-- for the project because it is not intended to be run on the target board.

-- with GNAT.IO; use GNAT.IO;
-- with GNAT.Serial_Communications; use GNAT.Serial_Communications;
--
-- procedure Host is
-- COM : aliased Serial_Port;
-- COM3 : constant Port_Name := Name (3);
--
-- Outgoing : String (1 .. 1024); -- arbitrary
-- Last : Natural;
-- begin
-- COM.Open (COM3);
-- COM.Set (Rate => B115200, Block => False);
--
-- loop
-- Put ("> ");
-- Get_Line (Outgoing, Last);
-- exit when Last = Outgoing'First - 1;
--
-- Put_Line ("Sending: '" & Outgoing (1 .. Last) & "'");
-- String'Output (COM'Access, Outgoing (1 .. Last));
--
-- declare
-- Incoming : constant String := String'Input (COM'Access);
-- begin
-- Put_Line ("From board: " & Incoming);
-- end;
-- end loop;
--
-- COM.Close;
-- end Host;

-- You can change the COM port number, or even get it from the command line
-- as an argument, but it must match what the host OS sees from the USB-COM
-- cable.

-- When running it, enter a string at the prompt (">") or just hit carriage
-- return if you are ready to quit. If you enter a string, it will be sent to
-- the target board, along with the bounds. The program (in this file) running
-- on the target, echos it back so the host app will show that response from
-- the board.
-- you will need to use a program on the host that uses streams to send and
-- receive these String values. The source code and GNAT project file for such
-- a program are in Ada_Drivers_Library/examples/shared/serial_ports/host_app/

-- TARGET BOARD SIDE:

-- This file declares the main procedure for the program running on the target
-- board. It simply echos the incoming strings, forever.

with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler);

with Serial_IO;
with Peripherals_Streaming; use Peripherals_Streaming;
with Serial_IO.Streaming; use Serial_IO.Streaming;

procedure Demo_Serial_Port_Streaming is
begin
Initialize_Hardware (COM);
Configure (COM, Baud_Rate => 115_200);
Serial_IO.Initialize_Hardware (Peripheral);
Serial_IO.Configure (COM.Device, Baud_Rate => 115_200);
-- This baud rate selection is entirely arbitrary. Note that you may
-- have to alter the settings of your host serial port to match this
-- baud rate, or just change the above to match whatever the host
-- serial port has set already. An application such as TerraTerm
-- or RealTerm is helpful.

loop
declare
-- get the incoming msg from the serial port
-- await the next msg from the serial port
Incoming : constant String := String'Input (COM'Access);
begin
-- echo the received msg content
String'Output (COM'Access, "Received '" & Incoming & "'");
String'Output (COM'Access, "You sent '" & Incoming & "'");
end;
end loop;
end Demo_Serial_Port_Streaming;
Loading
Loading