Serial port Ada:串行端口,字符串到流\u元素\u数组

Serial port Ada:串行端口,字符串到流\u元素\u数组,serial-port,ada,Serial Port,Ada,定义为: when 'B' |'b' => cons.Put_Line("Enter text - less than 20 chars: "); cons.Get_Line(Item => st, Last => m); --buffer_ser'Write(st,m); ser.Write(Port =>

定义为:

        when 'B' |'b' =>
           cons.Put_Line("Enter text - less than 20 chars:   ");
           cons.Get_Line(Item => st,
                         Last => m);

           --buffer_ser'Write(st,m);

           ser.Write(Port   => S_Port,
                     Buffer => buffer_ser);
基本上,我需要一个非常便携的应用程序来操作一个基于串行命令覆盖视频流的旧设备。我决定试试Ada,因为我一直在学习其他东西

如何从Ada中的字符串(1..20)转换为流元素数组(1..20)?我已经尝试了显而易见的答案,但我完全被卡住了

按照要求为投票否决我的人编辑…

首先我们需要一个MCVE

   package cons renames gnat.IO;
   package ser renames gnat.Serial_Communications;

   S_Port : gnat.Serial_Communications.Serial_Port;
   buffer_ser: ada.Streams.Stream_Element_Array(1..20);
   x : Ada.Streams.Stream_Element_Offset;
   m : Integer;
   st : string(1..20) := (others => ASCII.NUL);
   ComPort : GNAT.Serial_Communications.Port_Name(1..5);
它编译成功,但因错误而失败

引发GNAT.SERIAL_COMMUNICATIONS.SERIAL_错误:写入:端口不正确 打开

对Streams的一点阅读表明,实际问题的答案是:

如何转换为流元素数组(1..20)

is:通常情况下,你不会。我会帮你处理的

分别进行了几项修改:

  • 使S_端口具有别名,以便我们可以访问它(允许可重定向的流写入)并删除不必要的中间变量
  • 实际上,将串行端口作为流打开
  • 将字符串直接写入流

with gnat.IO;
with ada.Streams;
with gnat.Serial_Communications;

procedure MCVE is

   package cons renames gnat.IO;
   package ser renames gnat.Serial_Communications;

   S_Port : gnat.Serial_Communications.Serial_Port;
   buffer_ser: ada.Streams.Stream_Element_Array(1..20);
   x : Ada.Streams.Stream_Element_Offset;
   m : Integer;
   st : string(1..20) := (others => ASCII.NUL);
   ComPort : GNAT.Serial_Communications.Port_Name(1..5);

begin
           cons.Put_Line("Enter text - less than 20 chars:   ");
           cons.Get_Line(Item => st,
                         Last => m);

           --buffer_ser'Write(st,m);

           ser.Write(Port   => S_Port,
                     Buffer => buffer_ser);

end MCVE;
但是在不合适的时候使用固定长度的字符串是个坏主意。让我们声明字符串的长度正确,并进一步简化。这需要一个Get_Line函数形式,Gnat.IO包不提供该函数形式,因此让我们改用更便携的Ada.Text_IO。(并初始化串行端口名,实际使用重命名的软件包…)

当我们完成时,我们会有类似

S_Port : aliased gnat.Serial_Communications.Serial_Port;
-- buffer_ser: ada.Streams.Stream_Element_Array(1..20);
-- x : Ada.Streams.Stream_Element_Offset;
...
gnat.Serial_Communications.Open(S_Port,ComPort);
String'Write(S_Port'access, st(1..m));
--buffer_ser'Write(st,m);
--ser.Write(Port   => S_Port, Buffer => buffer_ser);

请在您的问题中包含代码,而不是图像。请阅读将此片段转换为MCVE我刚刚阅读了MCVE指南。这是我在不破坏最小部分的情况下所能做到的最好。具有讽刺意味的是,MCVE文档需要更清晰。这是一个循环——重复的重新声明会导致问题吗?我需要手动释放它,还是在循环结束时自动清除?这就是declare块的美妙之处:它“只工作”。虽然每次循环中变量的大小可能不同,但它们在
结束时超出了范围,并被自动释放(堆栈分配不是强制的,而是通常的实现。因此,不会因为这种简单性而失去效率)。您越不需要手动alloc/dealloc、使用单独“length”参数的固定长度字符串或其他折衷解决方案等技巧,就越不需要查找错误。不确定MCVE文档中关于“Complete”的不清楚之处。或“可验证”。文档要求您测试您提供的代码。。。declare块的另一个很好的特性是重构:它们很适合抽象为过程——可能是局部过程,因此局部变量在其他地方不太可能有用的情况下,在没有冗长的参数列表的情况下是可见的。
with Ada.Text_IO;
with ada.Streams;
with gnat.Serial_Communications;

procedure MCVE is

   package cons renames Ada.Text_IO;
   package ser renames gnat.Serial_Communications;

   S_Port : aliased ser.Serial_Port;
   ComPort : ser.Port_Name := "COM1";

begin
           ser.Open(S_Port,ComPort);

           cons.Put_Line("Enter text :   ");
           declare
              st : String := cons.Get_Line;
           begin
              String'Write(S_Port'access, st);
           end;
end MCVE;