diff --git a/examples/shared/serial_ports/host_app/README.md b/examples/shared/serial_ports/host_app/README.md new file mode 100644 index 000000000..c1110cc93 --- /dev/null +++ b/examples/shared/serial_ports/host_app/README.md @@ -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. \ No newline at end of file diff --git a/examples/shared/serial_ports/host_app/host.adb b/examples/shared/serial_ports/host_app/host.adb index ec10c25dd..c74910804 100644 --- a/examples/shared/serial_ports/host_app/host.adb +++ b/examples/shared/serial_ports/host_app/host.adb @@ -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 -- @@ -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 ("> "); @@ -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; diff --git a/examples/shared/serial_ports/src/demo_serial_port_blocking.adb b/examples/shared/serial_ports/src/demo_serial_port_blocking.adb index d53f6586f..7f8cdef62 100644 --- a/examples/shared/serial_ports/src/demo_serial_port_blocking.adb +++ b/examples/shared/serial_ports/src/demo_serial_port_blocking.adb @@ -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 -- @@ -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 @@ -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; diff --git a/examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb b/examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb index cdc0959f4..b2c394cbc 100644 --- a/examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb +++ b/examples/shared/serial_ports/src/demo_serial_port_nonblocking.adb @@ -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 -- @@ -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 @@ -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; diff --git a/examples/shared/serial_ports/src/demo_serial_port_streaming.adb b/examples/shared/serial_ports/src/demo_serial_port_streaming.adb index 05c5e0255..af3e0c119 100644 --- a/examples/shared/serial_ports/src/demo_serial_port_streaming.adb +++ b/examples/shared/serial_ports/src/demo_serial_port_streaming.adb @@ -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 -- @@ -44,59 +44,15 @@ -- 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: @@ -104,22 +60,26 @@ -- 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; diff --git a/examples/shared/serial_ports/src/peripherals_blocking.ads b/examples/shared/serial_ports/src/peripherals_blocking.ads index 0db5d6753..72161908d 100644 --- a/examples/shared/serial_ports/src/peripherals_blocking.ads +++ b/examples/shared/serial_ports/src/peripherals_blocking.ads @@ -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 -- @@ -39,12 +39,12 @@ package Peripherals_Blocking is -- the USART selection is arbitrary but the AF number and the pins must -- be those required by that USART - Peripheral : aliased Serial_IO.Peripheral_Descriptor := + Peripheral : constant Serial_IO.Peripheral_Descriptor := (Transceiver => USART_1'Access, Transceiver_AF => GPIO_AF_USART1_7, Tx_Pin => PB6, Rx_Pin => PB7); - COM : Blocking.Serial_Port (Peripheral'Access); + COM : Blocking.Serial_Port (Peripheral.Transceiver); end Peripherals_Blocking; diff --git a/examples/shared/serial_ports/src/peripherals_nonblocking.ads b/examples/shared/serial_ports/src/peripherals_nonblocking.ads index 8c41bbc4b..28766762f 100644 --- a/examples/shared/serial_ports/src/peripherals_nonblocking.ads +++ b/examples/shared/serial_ports/src/peripherals_nonblocking.ads @@ -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 -- @@ -43,13 +43,13 @@ package Peripherals_Nonblocking is -- the USART selection is arbitrary but the AF number and the pins must -- be those required by that USART - Peripheral : aliased Serial_IO.Peripheral_Descriptor := + Peripheral : constant Serial_IO.Peripheral_Descriptor := (Transceiver => USART_1'Access, Transceiver_AF => GPIO_AF_USART1_7, Tx_Pin => PB6, Rx_Pin => PB7); - COM : Nonblocking.Serial_Port (Device => Peripheral'Access, + COM : Nonblocking.Serial_Port (Device => Peripheral.Transceiver, IRQ => USART1_Interrupt, IRQ_Priority => Interrupt_Priority'Last); diff --git a/examples/shared/serial_ports/src/peripherals_streaming.ads b/examples/shared/serial_ports/src/peripherals_streaming.ads index 7a04559b1..7922c3b2e 100644 --- a/examples/shared/serial_ports/src/peripherals_streaming.ads +++ b/examples/shared/serial_ports/src/peripherals_streaming.ads @@ -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 -- @@ -29,21 +29,19 @@ -- -- ------------------------------------------------------------------------------ -with STM32.Device; use STM32.Device; - -with Serial_IO; use Serial_IO; -with Serial_IO.Streaming; +with STM32.Device; +with Serial_IO.Streaming; use Serial_IO; package Peripherals_Streaming is -- the USART selection is arbitrary but the AF number and the pins must -- be those required by that USART - Peripheral : aliased Serial_IO.Peripheral_Descriptor := - (Transceiver => USART_1'Access, - Transceiver_AF => GPIO_AF_USART1_7, - Tx_Pin => PB6, - Rx_Pin => PB7); + Peripheral : constant Serial_IO.Peripheral_Descriptor := + (Transceiver => STM32.Device.USART_1'Access, + Transceiver_AF => STM32.Device.GPIO_AF_USART1_7, + Tx_Pin => STM32.Device.PB6, + Rx_Pin => STM32.Device.PB7); - COM : aliased Streaming.Serial_Port (Peripheral'Access); + COM : aliased Streaming.Serial_Port (Peripheral.Transceiver); end Peripherals_Streaming; diff --git a/examples/shared/serial_ports/src/serial_io-blocking.adb b/examples/shared/serial_ports/src/serial_io-blocking.adb index c682f5e42..a024f492c 100644 --- a/examples/shared/serial_ports/src/serial_io-blocking.adb +++ b/examples/shared/serial_ports/src/serial_io-blocking.adb @@ -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 -- @@ -29,36 +29,10 @@ -- -- ------------------------------------------------------------------------------ -with STM32.Device; use STM32.Device; -with HAL; use HAL; +with HAL; package body Serial_IO.Blocking is - ------------------------- - -- Initialize_Hardware -- - ------------------------- - - procedure Initialize_Hardware (This : out Serial_Port) is - begin - Serial_IO.Initialize_Hardware (This.Device); - end Initialize_Hardware; - - --------------- - -- Configure -- - --------------- - - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control) - is - begin - Serial_IO.Configure (This.Device, Baud_Rate, Parity, Data_Bits, End_Bits, Control); - end Configure; - ---------- -- Send -- ---------- @@ -66,10 +40,9 @@ package body Serial_IO.Blocking is procedure Send (This : in out Serial_Port; Msg : not null access Message) is begin for Next in 1 .. Msg.Length loop - Await_Send_Ready (This.Device.Transceiver.all); - Transmit - (This.Device.Transceiver.all, - Character'Pos (Msg.Content_At (Next))); + Await_Send_Ready (This.Device); + This.Device.Transmit + (Character'Pos (Msg.Content_At (Next))); end loop; end Send; @@ -79,12 +52,12 @@ package body Serial_IO.Blocking is procedure Receive (This : in out Serial_Port; Msg : not null access Message) is Received_Char : Character; - Raw : UInt9; + Raw : HAL.UInt9; begin Msg.Clear; Receiving : for K in 1 .. Msg.Physical_Size loop - Await_Data_Available (This.Device.Transceiver.all); - Receive (This.Device.Transceiver.all, Raw); + Await_Data_Available (This.Device); + This.Device.Receive (Raw); Received_Char := Character'Val (Raw); exit Receiving when Received_Char = Msg.Terminator; Msg.Append (Received_Char); @@ -95,10 +68,10 @@ package body Serial_IO.Blocking is -- Await_Send_Ready -- ---------------------- - procedure Await_Send_Ready (This : USART) is + procedure Await_Send_Ready (This : access USART) is begin loop - exit when Tx_Ready (This); + exit when This.Tx_Ready; end loop; end Await_Send_Ready; @@ -106,10 +79,10 @@ package body Serial_IO.Blocking is -- Await_Data_Available -- -------------------------- - procedure Await_Data_Available (This : USART) is + procedure Await_Data_Available (This : access USART) is begin loop - exit when Rx_Ready (This); + exit when This.Rx_Ready; end loop; end Await_Data_Available; diff --git a/examples/shared/serial_ports/src/serial_io-blocking.ads b/examples/shared/serial_ports/src/serial_io-blocking.ads index 2e19b080e..a01c1aac9 100644 --- a/examples/shared/serial_ports/src/serial_io-blocking.ads +++ b/examples/shared/serial_ports/src/serial_io-blocking.ads @@ -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 -- @@ -45,34 +45,35 @@ with Message_Buffers; use Message_Buffers; package Serial_IO.Blocking is pragma Elaborate_Body; - type Serial_Port (Device : not null access Peripheral_Descriptor) is + type Serial_Port (Device : not null access USART) is tagged limited private; - procedure Initialize_Hardware (This : out Serial_Port); - - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control); - - procedure Send (This : in out Serial_Port; Msg : not null access Message); + procedure Send + (This : in out Serial_Port; + Msg : not null access Message); -- Sends Msg.Length characters of Msg via USART attached to This. Callers -- wait until all characters are sent. - procedure Receive (This : in out Serial_Port; Msg : not null access Message) with - Post => Msg.Length <= Msg.Physical_Size and - (if Msg.Length > 0 then Msg.Content_At (Msg.Length) /= Msg.Terminator); - -- Callers wait until all characters are received. + procedure Receive + (This : in out Serial_Port; + Msg : not null access Message) + with + Post => Msg.Length <= Msg.Physical_Size and then + -- At most Msg.Physical_Size characters are included + (if Msg.Length > 0 then + Msg.Content_At (Msg.Length) /= Msg.Terminator); + -- Reception completes if the terminator is received, and the + -- terminator is not included + + -- Callers to the above wait until all characters are received. private - type Serial_Port (Device : access Peripheral_Descriptor) is tagged limited null record; + type Serial_Port (Device : access USART) is + tagged limited null record; - procedure Await_Send_Ready (This : USART) with Inline; + procedure Await_Send_Ready (This : access USART) with Inline; - procedure Await_Data_Available (This : USART) with Inline; + procedure Await_Data_Available (This : access USART) with Inline; end Serial_IO.Blocking; diff --git a/examples/shared/serial_ports/src/serial_io-nonblocking.adb b/examples/shared/serial_ports/src/serial_io-nonblocking.adb index 2d95473bf..77618442c 100644 --- a/examples/shared/serial_ports/src/serial_io-nonblocking.adb +++ b/examples/shared/serial_ports/src/serial_io-nonblocking.adb @@ -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 -- @@ -33,31 +33,6 @@ with STM32.Device; use STM32.Device; package body Serial_IO.Nonblocking is - ------------------------- - -- Initialize_Hardware -- - ------------------------- - - procedure Initialize_Hardware (This : in out Serial_Port) is - begin - Serial_IO.Initialize_Hardware (This.Device); - end Initialize_Hardware; - - --------------- - -- Configure -- - --------------- - - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control) - is - begin - Serial_IO.Configure (This.Device, Baud_Rate, Parity, Data_Bits, End_Bits, Control); - end Configure; - ---------- -- Send -- ---------- @@ -91,13 +66,11 @@ package body Serial_IO.Nonblocking is -- if Word_Lenth = 9 then -- -- handle the extra byte required for the 9th bit -- else -- 8 data bits so no extra byte involved - Transmit - (Device.Transceiver.all, - Character'Pos (Outgoing_Msg.Content_At (Next_Out))); + Device.Transmit (Character'Pos (Outgoing_Msg.Content_At (Next_Out))); Next_Out := Next_Out + 1; -- end if; if Next_Out > Outgoing_Msg.Length then - Disable_Interrupts (Device.Transceiver.all, Source => Transmission_Complete); + Device.Disable_Interrupts (Source => Transmission_Complete); Outgoing_Msg.Signal_Transmission_Complete; Outgoing_Msg := null; end if; @@ -108,20 +81,20 @@ package body Serial_IO.Nonblocking is ---------------------- procedure Handle_Reception is - Received_Char : constant Character := Character'Val (Current_Input (Device.Transceiver.all)); + Received_Char : constant Character := Character'Val (Device.Current_Input); begin - if Received_Char /= Terminator (Incoming_Msg.all) then + if Received_Char /= Incoming_Msg.Terminator then Incoming_Msg.Append (Received_Char); end if; - if Received_Char = Incoming_Msg.Terminator or + if Received_Char = Incoming_Msg.Terminator or else Incoming_Msg.Length = Incoming_Msg.Physical_Size then -- reception complete loop -- wait for device to clear the status - exit when not Status (Device.Transceiver.all, Read_Data_Register_Not_Empty); + exit when not Device.Status (Read_Data_Register_Not_Empty); end loop; - Disable_Interrupts (Device.Transceiver.all, Source => Received_Data_Not_Empty); + Device.Disable_Interrupts (Source => Received_Data_Not_Empty); Incoming_Msg.Signal_Reception_Complete; Incoming_Msg := null; end if; @@ -134,50 +107,50 @@ package body Serial_IO.Nonblocking is procedure ISR is begin -- check for data arrival - if Status (Device.Transceiver.all, Read_Data_Register_Not_Empty) and - Interrupt_Enabled (Device.Transceiver.all, Received_Data_Not_Empty) + if Device.Status (Read_Data_Register_Not_Empty) and then + Device.Interrupt_Enabled (Received_Data_Not_Empty) then Detect_Errors (Is_Xmit_IRQ => False); Handle_Reception; - Clear_Status (Device.Transceiver.all, Read_Data_Register_Not_Empty); + Device.Clear_Status (Read_Data_Register_Not_Empty); end if; -- check for transmission ready - if Status (Device.Transceiver.all, Transmission_Complete_Indicated) and - Interrupt_Enabled (Device.Transceiver.all, Transmission_Complete) + if Device.Status (Transmission_Complete_Indicated) and then + Device.Interrupt_Enabled (Transmission_Complete) then Detect_Errors (Is_Xmit_IRQ => True); Handle_Transmission; - Clear_Status (Device.Transceiver.all, Transmission_Complete_Indicated); + Device.Clear_Status (Transmission_Complete_Indicated); end if; end ISR; - ------------------- - -- Start_Sending -- - ------------------- + ---------- + -- Send -- + ---------- procedure Start_Sending (Msg : not null access Message) is begin Outgoing_Msg := Msg; Next_Out := 1; - Enable_Interrupts (Device.Transceiver.all, Parity_Error); - Enable_Interrupts (Device.Transceiver.all, Error); - Enable_Interrupts (Device.Transceiver.all, Transmission_Complete); + Device.Enable_Interrupts (Parity_Error); + Device.Enable_Interrupts (Error); + Device.Enable_Interrupts (Transmission_Complete); end Start_Sending; - --------------------- - -- Start_Receiving -- - --------------------- + ------------- + -- Receive -- + ------------- procedure Start_Receiving (Msg : not null access Message) is begin Incoming_Msg := Msg; Incoming_Msg.Clear; - Enable_Interrupts (Device.Transceiver.all, Parity_Error); - Enable_Interrupts (Device.Transceiver.all, Error); - Enable_Interrupts (Device.Transceiver.all, Received_Data_Not_Empty); + Device.Enable_Interrupts (Parity_Error); + Device.Enable_Interrupts (Error); + Device.Enable_Interrupts (Received_Data_Not_Empty); end Start_Receiving; ------------------- @@ -186,10 +159,10 @@ package body Serial_IO.Nonblocking is procedure Detect_Errors (Is_Xmit_IRQ : Boolean) is begin - if Status (Device.Transceiver.all, Parity_Error_Indicated) and - Interrupt_Enabled (Device.Transceiver.all, Parity_Error) + if Device.Status (Parity_Error_Indicated) and then + Device.Interrupt_Enabled (Parity_Error) then - Clear_Status (Device.Transceiver.all, Parity_Error_Indicated); + Device.Clear_Status (Parity_Error_Indicated); if Is_Xmit_IRQ then Outgoing_Msg.Note_Error (Parity_Error_Detected); else @@ -197,10 +170,10 @@ package body Serial_IO.Nonblocking is end if; end if; - if Status (Device.Transceiver.all, Framing_Error_Indicated) and - Interrupt_Enabled (Device.Transceiver.all, Error) + if Device.Status (Framing_Error_Indicated) and then + Device.Interrupt_Enabled (Error) then - Clear_Status (Device.Transceiver.all, Framing_Error_Indicated); + Device.Clear_Status (Framing_Error_Indicated); if Is_Xmit_IRQ then Outgoing_Msg.Note_Error (Frame_Error_Detected); else @@ -208,10 +181,10 @@ package body Serial_IO.Nonblocking is end if; end if; - if Status (Device.Transceiver.all, USART_Noise_Error_Indicated) and - Interrupt_Enabled (Device.Transceiver.all, Error) + if Device.Status (USART_Noise_Error_Indicated) and then + Device.Interrupt_Enabled (Error) then - Clear_Status (Device.Transceiver.all, USART_Noise_Error_Indicated); + Device.Clear_Status (USART_Noise_Error_Indicated); if Is_Xmit_IRQ then Outgoing_Msg.Note_Error (Noise_Error_Detected); else @@ -219,10 +192,10 @@ package body Serial_IO.Nonblocking is end if; end if; - if Status (Device.Transceiver.all, Overrun_Error_Indicated) and - Interrupt_Enabled (Device.Transceiver.all, Error) + if Device.Status (Overrun_Error_Indicated) and then + Device.Interrupt_Enabled (Error) then - Clear_Status (Device.Transceiver.all, Overrun_Error_Indicated); + Device.Clear_Status (Overrun_Error_Indicated); if Is_Xmit_IRQ then Outgoing_Msg.Note_Error (Overrun_Error_Detected); else diff --git a/examples/shared/serial_ports/src/serial_io-nonblocking.ads b/examples/shared/serial_ports/src/serial_io-nonblocking.ads index 06b9c4c83..dde343f8f 100644 --- a/examples/shared/serial_ports/src/serial_io-nonblocking.ads +++ b/examples/shared/serial_ports/src/serial_io-nonblocking.ads @@ -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 -- @@ -50,27 +50,14 @@ package Serial_IO.Nonblocking is pragma Elaborate_Body; type Serial_Port - (Device : not null access Peripheral_Descriptor; + (Device : not null access USART; IRQ : Interrupt_ID; IRQ_Priority : Interrupt_Priority) is limited private; - procedure Initialize_Hardware (This : in out Serial_Port); - -- A convenience wrapper for Serial_IO.Initialize_Hardware - - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control); - -- A convenience wrapper for Serial_IO.Configure - procedure Send (This : in out Serial_Port; - Msg : not null access Message) - with Inline; + Msg : not null access Message); -- Start sending the content of Msg.all, returning potentially -- prior to the completion of the message transmission @@ -79,25 +66,21 @@ package Serial_IO.Nonblocking is Msg : not null access Message) with Post => Msg.Length <= Msg.Physical_Size and - (if Msg.Length > 0 then Msg.Content_At (Msg.Length) /= Msg.Terminator), - Inline; + (if Msg.Length > 0 then Msg.Content_At (Msg.Length) /= Msg.Terminator); -- Start receiving Msg.all content, ending when the specified - -- Msg.Terminator character is received (it is not stored), or - -- the physical capacity of Msg.all is reached + -- Msg.Terminator character is received or the physical capacity + -- of Msg.all is reached. The terminator character is not stored. private protected type Serial_Port - (Device : not null access Peripheral_Descriptor; + (Device : not null access USART; IRQ : Interrupt_ID; IRQ_Priority : Interrupt_Priority) - -- with - -- Interrupt_Priority => IRQ_Priority + with + Interrupt_Priority => IRQ_Priority is - pragma Interrupt_Priority (IRQ_Priority); - -- use pragma as workaround for bug in CE_2021 frontend (V523-041) - procedure Start_Sending (Msg : not null access Message); procedure Start_Receiving (Msg : not null access Message); diff --git a/examples/shared/serial_ports/src/serial_io-streaming.adb b/examples/shared/serial_ports/src/serial_io-streaming.adb index 209650031..e8448e261 100644 --- a/examples/shared/serial_ports/src/serial_io-streaming.adb +++ b/examples/shared/serial_ports/src/serial_io-streaming.adb @@ -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 -- @@ -29,65 +29,39 @@ -- -- ------------------------------------------------------------------------------ -with STM32.Device; use STM32.Device; -with HAL; use HAL; +with HAL; package body Serial_IO.Streaming is - ------------------------- - -- Initialize_Hardware -- - ------------------------- - - procedure Initialize_Hardware (This : out Serial_Port) is - begin - Serial_IO.Initialize_Hardware (This.Device); - end Initialize_Hardware; - - --------------- - -- Configure -- - --------------- + ---------------------- + -- Set_Read_Timeout -- + ---------------------- - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control) + procedure Set_Read_Timeout + (This : in out Serial_Port; + Wait : Time_Span) is begin - Serial_IO.Configure (This.Device, Baud_Rate, Parity, Data_Bits, End_Bits, Control); - end Configure; + This.Timeout := Wait; + end Set_Read_Timeout; ---------------------- -- Await_Send_Ready -- ---------------------- - procedure Await_Send_Ready (This : USART) is + procedure Await_Send_Ready (This : access USART) is begin loop - exit when Tx_Ready (This); + exit when This.Tx_Ready; end loop; end Await_Send_Ready; - ---------------------- - -- Set_Read_Timeout -- - ---------------------- - - procedure Set_Read_Timeout - (This : in out Serial_Port; - Wait : Time_Span) - is - begin - This.Timeout := Wait; - end Set_Read_Timeout; - -------------------------- -- Await_Data_Available -- -------------------------- procedure Await_Data_Available - (This : USART; + (This : access USART; Timeout : Time_Span := Time_Span_Last; Timed_Out : out Boolean) is @@ -95,7 +69,7 @@ package body Serial_IO.Streaming is begin Timed_Out := True; while Clock < Deadline loop - if Rx_Ready (This) then + if This.Rx_Ready then Timed_Out := False; exit; end if; @@ -113,8 +87,8 @@ package body Serial_IO.Streaming is is begin if First = Stream_Element_Offset'First and then Count = 0 then - -- we need to return First - 1, but cannot - raise Constraint_Error; -- per RM + -- although we intend to return First - 1, we cannot + raise Constraint_Error; -- per AI95-227 else return First + Stream_Element_Offset (Count) - 1; end if; @@ -130,14 +104,14 @@ package body Serial_IO.Streaming is Buffer : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset) is - Raw : UInt9; + Raw : HAL.UInt9; Timed_Out : Boolean; Count : Long_Integer := 0; begin Receiving : for K in Buffer'Range loop - Await_Data_Available (This.Device.Transceiver.all, This.Timeout, Timed_Out); + Await_Data_Available (This.Device, This.Timeout, Timed_Out); exit Receiving when Timed_Out; - Receive (This.Device.Transceiver.all, Raw); + This.Device.Receive (Raw); Buffer (K) := Stream_Element (Raw); Count := Count + 1; end loop Receiving; @@ -155,8 +129,8 @@ package body Serial_IO.Streaming is is begin for Next of Buffer loop - Await_Send_Ready (This.Device.Transceiver.all); - Transmit (This.Device.Transceiver.all, Stream_Element'Pos (Next)); + Await_Send_Ready (This.Device); + This.Device.Transmit (HAL.UInt9 (Next)); end loop; end Write; diff --git a/examples/shared/serial_ports/src/serial_io-streaming.ads b/examples/shared/serial_ports/src/serial_io-streaming.ads index b931570e9..9e86f18d0 100644 --- a/examples/shared/serial_ports/src/serial_io-streaming.ads +++ b/examples/shared/serial_ports/src/serial_io-streaming.ads @@ -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 -- @@ -43,27 +43,17 @@ with Ada.Real_Time; use Ada.Real_Time; package Serial_IO.Streaming is pragma Elaborate_Body; - type Serial_Port (Device : not null access Peripheral_Descriptor) is + type Serial_Port (Device : not null access USART) is new Ada.Streams.Root_Stream_Type with private; - procedure Initialize_Hardware (This : out Serial_Port); - - procedure Configure - (This : in out Serial_Port; - Baud_Rate : Baud_Rates; - Parity : Parities := No_Parity; - Data_Bits : Word_Lengths := Word_Length_8; - End_Bits : Stop_Bits := Stopbits_1; - Control : Flow_Control := No_Flow_Control); - procedure Set_Read_Timeout (This : in out Serial_Port; Wait : Time_Span); -- Stream attributes that call Read (below) can either wait indefinitely or -- can be set to return any current values received after a given interval. - -- If the value Time_Span_Last is passed to Wait, the effect is essentially to wait - -- forever, i.e., blocking. That is also the effect if this routine is - -- never called. + -- If the value Time_Span_Last is passed to Wait, the effect is essentially + -- to wait forever, i.e., blocking. That is also the effect if this routine + -- is never called. overriding procedure Read @@ -78,15 +68,15 @@ package Serial_IO.Streaming is private - type Serial_Port (Device : access Peripheral_Descriptor) is + type Serial_Port (Device : access USART) is new Ada.Streams.Root_Stream_Type with record Timeout : Time_Span := Time_Span_Last; end record; - procedure Await_Send_Ready (This : USART) with Inline; + procedure Await_Send_Ready (This : access USART) with Inline; procedure Await_Data_Available - (This : USART; + (This : access USART; Timeout : Time_Span := Time_Span_Last; Timed_Out : out Boolean) with Inline; diff --git a/examples/shared/serial_ports/src/serial_io.adb b/examples/shared/serial_ports/src/serial_io.adb index dc50a2aff..a6c8c25e9 100644 --- a/examples/shared/serial_ports/src/serial_io.adb +++ b/examples/shared/serial_ports/src/serial_io.adb @@ -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 -- @@ -37,7 +37,7 @@ package body Serial_IO is -- Initialize_Hardware -- ------------------------- - procedure Initialize_Hardware (Device : access Peripheral_Descriptor) is + procedure Initialize_Hardware (Device : Peripheral_Descriptor) is Configuration : GPIO_Port_Configuration; Device_Pins : constant GPIO_Points := Device.Rx_Pin & Device.Tx_Pin; begin @@ -58,24 +58,27 @@ package body Serial_IO is --------------- procedure Configure - (Device : access Peripheral_Descriptor; + (Device : access USART; Baud_Rate : Baud_Rates; Parity : Parities := No_Parity; Data_Bits : Word_Lengths := Word_Length_8; End_Bits : Stop_Bits := Stopbits_1; Control : Flow_Control := No_Flow_Control) is + -- this is a convenience procedure, but the convenience includes + -- ensuring that the device is disabled and enabled at the appropriate + -- points begin - Disable (Device.Transceiver.all); + Device.Disable; - Set_Baud_Rate (Device.Transceiver.all, Baud_Rate); - Set_Mode (Device.Transceiver.all, Tx_Rx_Mode); - Set_Stop_Bits (Device.Transceiver.all, End_Bits); - Set_Word_Length (Device.Transceiver.all, Data_Bits); - Set_Parity (Device.Transceiver.all, Parity); - Set_Flow_Control (Device.Transceiver.all, Control); + Device.Set_Baud_Rate (Baud_Rate); + Device.Set_Mode (Tx_Rx_Mode); + Device.Set_Stop_Bits (End_Bits); + Device.Set_Word_Length (Data_Bits); + Device.Set_Parity (Parity); + Device.Set_Flow_Control (Control); - Enable (Device.Transceiver.all); + Device.Enable; end Configure; end Serial_IO; diff --git a/examples/shared/serial_ports/src/serial_io.ads b/examples/shared/serial_ports/src/serial_io.ads index a9a9f6c56..5d61f47cc 100644 --- a/examples/shared/serial_ports/src/serial_io.ads +++ b/examples/shared/serial_ports/src/serial_io.ads @@ -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 -- @@ -42,11 +42,11 @@ package Serial_IO is Rx_Pin : GPIO_Point; end record; - procedure Initialize_Hardware (Device : access Peripheral_Descriptor); + procedure Initialize_Hardware (Device : Peripheral_Descriptor); -- enable clocks, configure GPIO pins, etc. procedure Configure - (Device : access Peripheral_Descriptor; + (Device : access USART; Baud_Rate : Baud_Rates; Parity : Parities := No_Parity; Data_Bits : Word_Lengths := Word_Length_8;