Skip to content

Commit 52d4596

Browse files
authored
Merge pull request #448 from pat-rogers/master
Extensively refine code for these three serial I/O examples
2 parents 17d7b4b + a8bd479 commit 52d4596

16 files changed

+299
-346
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
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.
2+
3+
The other demonstration mains do not use streams. For those, use a host app such as TerraTerm or RealTerm.

examples/shared/serial_ports/host_app/host.adb

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
------------------------------------------------------------------------------
22
-- --
3-
-- Copyright (C) 2016, AdaCore --
3+
-- Copyright (C) 2016-2025, AdaCore --
44
-- --
55
-- Redistribution and use in source and binary forms, with or without --
66
-- modification, are permitted provided that the following conditions are --
@@ -30,37 +30,117 @@
3030
------------------------------------------------------------------------------
3131

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

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

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

46-
-- When running it, enter a string at the prompt (">") or just hit carriage
50+
-- On the command line invocation you must specify the host serial port number
51+
-- as an integer number (in any base if you use Ada syntax). That number must
52+
-- correspond to the host serial port connected to the target board. No other
53+
-- command line parameters are accepted.
54+
55+
-- During execution, enter a string at the prompt (">") or just hit carriage
4756
-- return if you are ready to quit. If you do enter a string, it will be sent
4857
-- to the target board, along with the bounds. The program running on the
4958
-- target echos it back so this host app will show that response from the
5059
-- board.
60+
--
61+
-- Note that the baud rate for the host serial port is set below, and although
62+
-- arbitrary, must match the value set by the streaming demo program on the
63+
-- target board. That could be an additional host argument in the future. The
64+
-- target serial port is set to eight data bits, no parity, and one stop bit.
65+
-- Those settings are typically what a host serial port uses for defaults, but
66+
-- not necessarily.
5167

5268
with GNAT.IO; use GNAT.IO;
5369
with GNAT.Serial_Communications; use GNAT.Serial_Communications;
70+
with Ada.Command_Line;
5471

5572
procedure Host is
56-
COM : aliased Serial_Port;
57-
COM3 : constant Port_Name := Name (3);
73+
74+
COM : aliased Serial_Port;
75+
Selected_Port : Integer;
76+
Valid_Selection : Boolean;
5877

5978
Outgoing : String (1 .. 1024); -- arbitrary
60-
Last : Natural;
79+
Last : Natural range Outgoing'First - 1 .. Outgoing'Last;
80+
81+
procedure Get_Port_Number
82+
(Selected_Port : out Integer;
83+
Valid : out Boolean);
84+
-- Get the port number from the command line arguments (only one is
85+
-- expected), ensuring that the argument is a well-formed integer with
86+
-- the required range.
87+
--
88+
-- Note that it does not check whether a valid argument corresponds to an
89+
-- existing host serial port. If it does not, GNAT.Serial_Communications
90+
-- will raise Serial_Error when Open is called.
91+
92+
---------------------
93+
-- Get_Port_Number --
94+
---------------------
95+
96+
procedure Get_Port_Number
97+
(Selected_Port : out Integer;
98+
Valid : out Boolean)
99+
is
100+
use Ada.Command_Line;
101+
begin
102+
Valid := False;
103+
Selected_Port := 0; -- won't be used unless the caller ignores Valid
104+
105+
if Argument_Count /= 1 then
106+
Put_Line ("You must specify (only) the number of the COM port to open on this host.");
107+
Put_Line ("For example, to specify COM3 the invocation would be:");
108+
Put_Line (" host 3");
109+
Put_Line ("The following Windows PowerShell command lists all existing ports:");
110+
Put_Line (" [System.IO.Ports.SerialPort]::GetPortNames()");
111+
return;
112+
end if;
113+
114+
Well_Formed : begin
115+
Selected_Port := Integer'Value (Argument (1));
116+
exception
117+
when others =>
118+
Put_Line ("You must specify a syntactically valid (positive) integer value for the host COM port.");
119+
return;
120+
end Well_Formed;
121+
122+
if Selected_Port < 1 then
123+
Put_Line ("You must specify a positive number for the host COM port.");
124+
-- Because function Name from package GNAT.Serial_Communications
125+
-- requires a positive value.
126+
return;
127+
end if;
128+
129+
Valid := True;
130+
end Get_Port_Number;
131+
61132
begin
62-
COM.Open (COM3);
133+
Get_Port_Number (Selected_Port, Valid_Selection);
134+
if not Valid_Selection then
135+
return;
136+
end if;
137+
138+
COM.Open (Name (Selected_Port));
63139
COM.Set (Rate => B115200, Block => False);
140+
-- The baud rate is arbitrary but must match the selection by the target
141+
-- board's stream demonstration program. The other target serial port
142+
-- settings are N81. That stop bit is likley critical to proper function
143+
-- of the demo.
64144

65145
loop
66146
Put ("> ");
@@ -74,7 +154,7 @@ begin
74154
declare
75155
Incoming : constant String := String'Input (COM'Access);
76156
begin
77-
Put_Line ("From board: " & Incoming);
157+
Put_Line ("Received from board: " & Incoming);
78158
end;
79159
end loop;
80160

examples/shared/serial_ports/src/demo_serial_port_blocking.adb

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
------------------------------------------------------------------------------
22
-- --
3-
-- Copyright (C) 2015-2022, AdaCore --
3+
-- Copyright (C) 2015-2025, AdaCore --
44
-- --
55
-- Redistribution and use in source and binary forms, with or without --
66
-- modification, are permitted provided that the following conditions are --
@@ -37,12 +37,10 @@ with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler);
3737
-- an exception is propagated. We need it in the executable, therefore it
3838
-- must be somewhere in the closure of the context clauses.
3939

40-
with Peripherals_Blocking; use Peripherals_Blocking;
40+
with Peripherals_Blocking; use Peripherals_Blocking; -- for COM
4141
with Serial_IO.Blocking; use Serial_IO.Blocking;
4242
with Message_Buffers; use Message_Buffers;
4343

44-
use Serial_IO;
45-
4644
procedure Demo_Serial_Port_Blocking is
4745

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

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

6466
Incoming.Set_Terminator (To => ASCII.CR);
6567
Send ("Enter text, terminated by CR.");
68+
-- Note that you may have to alter the settings on your host serial port
69+
-- so that the terminator char is not stripped off automatically by the
70+
-- host driver, which may happen especially when CR is the terminator.
71+
-- An application such as TerraTerm or RealTerm is helpful.
72+
6673
loop
67-
Blocking.Receive (COM, Incoming'Unchecked_Access);
74+
Receive (COM, Incoming'Unchecked_Access);
6875
Send ("Received : " & Incoming.Content);
6976
end loop;
7077
end Demo_Serial_Port_Blocking;

examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
------------------------------------------------------------------------------
22
-- --
3-
-- Copyright (C) 2015-2022, AdaCore --
3+
-- Copyright (C) 2015-2025, AdaCore --
44
-- --
55
-- Redistribution and use in source and binary forms, with or without --
66
-- modification, are permitted provided that the following conditions are --
@@ -29,9 +29,9 @@
2929
-- --
3030
------------------------------------------------------------------------------
3131

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

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

45-
use Serial_IO;
46-
4745
procedure Demo_Serial_Port_Nonblocking is
4846

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

52-
procedure Send (This : String);
50+
procedure Start_Sending (This : String);
5351

54-
procedure Send (This : String) is
52+
procedure Start_Sending (This : String) is
5553
begin
5654
Set (Outgoing, To => This);
57-
Nonblocking.Send (COM, Outgoing'Unchecked_Access);
58-
Await_Transmission_Complete (Outgoing);
59-
-- Send can/will return before the entire message has been sent
60-
end Send;
55+
Send (COM, Outgoing'Unchecked_Access);
56+
Outgoing.Await_Transmission_Complete;
57+
-- We wait anyway, just to keep things simple for the display
58+
end Start_Sending;
6159

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

6668
Incoming.Set_Terminator (To => ASCII.CR);
67-
Send ("Enter text, terminated by CR.");
69+
Start_Sending ("Enter text, terminated by CR.");
70+
-- Note that you may have to alter the settings on your host serial port so
71+
-- that the terminator char is not stripped off automatically by the host
72+
-- driver, which may happen especially when CR is the terminator. You may
73+
-- find that an application such as TerraTerm or RealTerm is helpful.
74+
6875
loop
69-
Nonblocking.Receive (COM, Incoming'Unchecked_Access);
70-
Await_Reception_Complete (Incoming);
71-
Send ("Received : " & Incoming.Content);
76+
Receive (COM, Incoming'Unchecked_Access);
77+
Incoming.Await_Reception_Complete;
78+
-- We wait anyway, just to keep things simple for the display
79+
Start_Sending ("Received : " & Incoming.Content);
7280
end loop;
7381
end Demo_Serial_Port_Nonblocking;
7482

Lines changed: 17 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
------------------------------------------------------------------------------
22
-- --
3-
-- Copyright (C) 2016-2022, AdaCore --
3+
-- Copyright (C) 2016-2025, AdaCore --
44
-- --
55
-- Redistribution and use in source and binary forms, with or without --
66
-- modification, are permitted provided that the following conditions are --
@@ -44,82 +44,42 @@
4444
-- HOST COMPUTER SIDE:
4545

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

5251
-- Note that, because it uses the stream attributes String'Output and
5352
-- String'Input, which write and read the bounds as well as the characters,
54-
-- you will need to use a program on the host that uses streams to send
55-
-- and receive these String values. Here is a sample interactive program,
56-
-- hardcoded arbitrarily to use COM3 on Windows. Note that the source code for
57-
-- this program is included in the root of this project, not in the source dir
58-
-- for the project because it is not intended to be run on the target board.
59-
60-
-- with GNAT.IO; use GNAT.IO;
61-
-- with GNAT.Serial_Communications; use GNAT.Serial_Communications;
62-
--
63-
-- procedure Host is
64-
-- COM : aliased Serial_Port;
65-
-- COM3 : constant Port_Name := Name (3);
66-
--
67-
-- Outgoing : String (1 .. 1024); -- arbitrary
68-
-- Last : Natural;
69-
-- begin
70-
-- COM.Open (COM3);
71-
-- COM.Set (Rate => B115200, Block => False);
72-
--
73-
-- loop
74-
-- Put ("> ");
75-
-- Get_Line (Outgoing, Last);
76-
-- exit when Last = Outgoing'First - 1;
77-
--
78-
-- Put_Line ("Sending: '" & Outgoing (1 .. Last) & "'");
79-
-- String'Output (COM'Access, Outgoing (1 .. Last));
80-
--
81-
-- declare
82-
-- Incoming : constant String := String'Input (COM'Access);
83-
-- begin
84-
-- Put_Line ("From board: " & Incoming);
85-
-- end;
86-
-- end loop;
87-
--
88-
-- COM.Close;
89-
-- end Host;
90-
91-
-- You can change the COM port number, or even get it from the command line
92-
-- as an argument, but it must match what the host OS sees from the USB-COM
93-
-- cable.
94-
95-
-- When running it, enter a string at the prompt (">") or just hit carriage
96-
-- return if you are ready to quit. If you enter a string, it will be sent to
97-
-- the target board, along with the bounds. The program (in this file) running
98-
-- on the target, echos it back so the host app will show that response from
99-
-- the board.
53+
-- you will need to use a program on the host that uses streams to send and
54+
-- receive these String values. The source code and GNAT project file for such
55+
-- a program are in Ada_Drivers_Library/examples/shared/serial_ports/host_app/
10056

10157
-- TARGET BOARD SIDE:
10258

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

10662
with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler);
107-
63+
with Serial_IO;
10864
with Peripherals_Streaming; use Peripherals_Streaming;
109-
with Serial_IO.Streaming; use Serial_IO.Streaming;
11065

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

11676
loop
11777
declare
118-
-- get the incoming msg from the serial port
78+
-- await the next msg from the serial port
11979
Incoming : constant String := String'Input (COM'Access);
12080
begin
12181
-- echo the received msg content
122-
String'Output (COM'Access, "Received '" & Incoming & "'");
82+
String'Output (COM'Access, "You sent '" & Incoming & "'");
12383
end;
12484
end loop;
12585
end Demo_Serial_Port_Streaming;

0 commit comments

Comments
 (0)