From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,7e490a18b9688bd9 X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII Received: by 10.68.21.67 with SMTP id t3mr1264468pbe.26.1316119710973; Thu, 15 Sep 2011 13:48:30 -0700 (PDT) Path: m9ni7025pbd.0!nntp.google.com!news1.google.com!goblin1!goblin.stu.neva.ru!feeder.news-service.com!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Stream_Element_Array Date: Thu, 15 Sep 2011 22:48:24 +0200 Organization: cbb software GmbH Message-ID: References: <1e6rw4vto3ldb.i8d7fxixapx4.dlg@40tude.net> <28u4e86fk8gn$.ialexttobgr0$.dlg@40tude.net> <276b8d0a-5b3c-4559-a275-98620657cc2f@s30g2000pri.googlegroups.com> <01c12338-e9f8-49ab-863d-c8282be3875e@g31g2000yqh.googlegroups.com> <1esmml9qftomp.vihelaijmcar$.dlg@40tude.net> Reply-To: mailbox@dmitry-kazakov.de NNTP-Posting-Host: 59aw/Kp5O6vHcepH4rjrvQ.user.speranza.aioe.org Mime-Version: 1.0 X-Complaints-To: abuse@aioe.org User-Agent: 40tude_Dialog/2.0.15.1 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news1.google.com comp.lang.ada:17980 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit Date: 2011-09-15T22:48:24+02:00 List-Id: On Thu, 15 Sep 2011 11:58:21 -0700 (PDT), Alexander Korolev wrote: > On Sep 15, 12:20�pm, "Dmitry A. Kazakov" > wrote: >> On Wed, 14 Sep 2011 14:29:41 -0700 (PDT), Alexander Korolev wrote: >>> "In your case the other end is not the memory but the wire" >>> I am not sure I undestand you complitly. What's wrong, at least for >>> now, to build \ construct in memory the Buffer (Stream_Element_Array) >>> with full command (according the format I posted) inside and after >>> that send it over any stream (including GNAT.Serial, Socket etc) >>> derived from Root_Stream_Type. Basicly, I don't need even a Type - >>> I am using it just get Unsigned_16 serialized into Stream Elements. >> >> Yes, but in most cases it does not work so straightforwardly. You usually >> need headers, checksums etc. The point is that you have more layers of the >> protocol than just raw values over stream of octets. This is why you use >> stream rather as a transport for packets/messages and often more upper >> levels too (state machine etc). The idea is to always encapsulate each >> level into a data type. It saves much time later. >> >>> That's it. It's kind of hadcrafting. I also can override My_Type'Write >>> attribute and send to Serial port ... Your approach is to create a new >>> stream actully, which will take into account the PROTOCOL specifics. >>> Absolutly agree with that. But what is wrong with manual approach I am >>> implementing. >> >> It is not wrong, it is just might not work because protocols are more >> complex (layered) than this simple model. > > 1. Can not disagree again - layers, state machines is "must" part. > 2. So far got some interim results with serialization of the Type > in Volatile Stream. The Last set to 3? It looks I am getting > there but no confidence so far. Volatile Stream has a bug in its implementation. Last is actually "Next". Anyway, here is how I do such stuff: with Volatile_Streams; use Volatile_Streams; with Ada.Streams; use Ada.Streams; with Interfaces; use Interfaces; package Frame_Streams is Protocol_Error : exception; -- -- Implements frame I/O layer over the stream transport. -- In this case the transport is memory-resident stream. -- type Frame_Stream (Size : Stream_Element_Count) is tagged limited private; -- Send frame, Data is the frame body procedure Send ( Stream : in out Frame_Stream; Data : Stream_Element_Array ); -- Receive frame, Data is the frame body, Last its last item -- Protocol_Error is propagated upon protocol errors procedure Receive ( Stream : in out Frame_Stream; Data : out Stream_Element_Array; Last : out Stream_Element_Offset ); private Max_Frame_Size : constant := 256; type Frame_Stream (Size : Stream_Element_Count) is new Memory_Resident_Stream (Size) with record Output : Stream_Element_Array (1..Max_Frame_Size); end record; end Frame_Streams; package body Frame_Streams is procedure Send ( Stream : in out Frame_Stream; Data : Stream_Element_Array ) is Sum : Unsigned_8 := 0; begin if Data'Length + 4 > Stream.Output'Length then raise Constraint_Error with "Packet is too large"; end if; Stream.Output (1) := 0; Stream.Output (2) := Stream_Element'Val (Data'Length / 256); Stream.Output (3) := Stream_Element'Val (Data'Length mod 256); Stream.Output (4..3 + Data'Length) := Data; for Index in Stream_Element_Offset range 2..3 + Data'Length loop Sum := Sum + Stream_Element'Pos (Stream.Output (Index)); end loop; Stream.Output (4 + Data'Length) := Stream_Element'Val (Sum); Stream.Write (Stream.Output (1..4 + Data'Length)); end Send; procedure Receive ( Stream : in out Frame_Stream; Data : out Stream_Element_Array; Last : out Stream_Element_Offset ) is Length : Stream_Element_Offset; Sum : Unsigned_8; Input : Stream_Element_Array (1..2); begin Stream.Read (Input (1..1), Last); if Last /= 2 then raise Protocol_Error with "Frame header expected"; elsif Input (1) /= 0 then raise Protocol_Error with "Wrong leading byte"; end if; Stream.Read (Input (1..2), Last); Length := Stream_Element'Pos (Input (1)) * 256 + Stream_Element'Pos (Input (2)); if Last /= 3 then raise Protocol_Error with "Unexpected end of stream"; elsif Length > Data'Length then raise Protocol_Error with "Frame is too large"; end if; Sum := Stream_Element'Pos (Input (1)) + Stream_Element'Pos (Input (2)); Stream.Read (Data (Data'First..Data'First + Length - 1), Last); if Last /= Data'First + Length then raise Protocol_Error with "Unexpected end of stream"; end if; Stream.Read (Input (1..1), Last); if Last /= 2 then raise Protocol_Error with "Unexpected end of stream"; end if; Last := Data'First + Length - 1; for Index in Data'First..Last loop Sum := Sum + Stream_Element'Pos (Data (Index)); end loop; if Sum /= Stream_Element'Pos (Input (1)) then raise Protocol_Error with "Checksum error"; end if; end Receive; end Frame_Streams; To be used as follows: with Ada.Text_IO; use Ada.Text_IO; with Frame_Streams; use Frame_Streams; procedure Put (Data : Stream_Element_Array) is begin for Index in Data'Range loop Put (Stream_Element'Image (Data (Index))); Put (' '); end loop; end Put; S : aliased Frame_Stream (1024); Buffer : Stream_Element_Array (1..4); Last : Stream_Element_Offset; begin S.Send ((1, 2, 3, 4)); Put_Line ("Written:" & Stream_Element_Count'Image (S.Extent)); S.Receive (Buffer, Last); Put_Line ("Read:"); Put (Buffer (1..Last)); end; Note that is in its turn is frame I/O layer. Upon it you will have another layer and so on up to the application layer. P.S. It is a bit simplified, if there are many transports layers, the frame layer would take the actual transport as a discriminant (access to Root_Stream'Class) or a generic parameter. In your case it would be an overkill. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de