Added arrays to queues.
Change-Id: Ifcb5ff0ecdbd47e7fa445275195cd7a87e96c20a
diff --git a/aos/build/queues/cpp_pretty_print/dep_file_pair.rb b/aos/build/queues/cpp_pretty_print/dep_file_pair.rb
index c13bb9e..63b3fbd 100644
--- a/aos/build/queues/cpp_pretty_print/dep_file_pair.rb
+++ b/aos/build/queues/cpp_pretty_print/dep_file_pair.rb
@@ -326,7 +326,7 @@
state.pp("template < ")
state.pp(@t_args)
else
- state.pp("template <")
+ state.pp("template < ")
end
state.pp(">\n")
end
diff --git a/aos/build/queues/cpp_pretty_print/file_pair_types.rb b/aos/build/queues/cpp_pretty_print/file_pair_types.rb
index 8f60b77..25ce4fe 100644
--- a/aos/build/queues/cpp_pretty_print/file_pair_types.rb
+++ b/aos/build/queues/cpp_pretty_print/file_pair_types.rb
@@ -157,7 +157,7 @@
state.pp("template < ")
state.pp(@t_args)
else
- state.pp("template <")
+ state.pp("template < ")
end
state.pp(">\n")
state.pp("class #@name")
diff --git a/aos/build/queues/objects/queue.rb b/aos/build/queues/objects/queue.rb
index 610bdf7..81cd181 100644
--- a/aos/build/queues/objects/queue.rb
+++ b/aos/build/queues/objects/queue.rb
@@ -84,16 +84,21 @@
check_type_error(locals)
if(@is_struct_type)
tval = lookup_type(locals)
- member = Target::MessageStructElement.new(tval, name)
+ member = Target::MessageStructElement.new(tval, @name)
+ if (@length != nil)
+ inner_member = member
+ member = Target::MessageArrayElement.new(inner_member, @length)
+ end
else
- if(@length == nil)
- member = Target::MessageElement.new(@type,@name)
- else
- member = Target::MessageArrayElement.new(@type,@name,@length)
- end
+ member = Target::MessageElement.new(@type,@name)
member.size = size()
member.zero = Zero[@type] || "0";
member.printformat = toPrintFormat()
+
+ if(@length != nil)
+ inner_member = member
+ member = Target::MessageArrayElement.new(inner_member,@length)
+ end
end
locals.local.add_member(member)
end
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index 903a872..36300ea 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -16,7 +16,7 @@
if(member.respond_to?(:add_TypeRegister))
register_members.push(member)
end
- fields << "new ::aos::MessageType::Field{#{tId}, #{fieldName}}"
+ fields << "new ::aos::MessageType::Field{#{tId}, #{member.respond_to?(:length) ? member.length : 0}, #{fieldName}}"
end
register_members.uniq do |member|
member.type
@@ -35,12 +35,12 @@
type_class.add_member(cons)
@members.each do |member|
if member.respond_to?(:type_name)
- type_name = member.type_name(cpp_tree)
+ type_name = "#{member.type_name(cpp_tree)} #{member.name}_in"
else
- type_name = member.type
+ type_name = member.create_usage(cpp_tree, "#{member.name}_in")
end
- cons.args << "#{type_name} #{member.name}_in"
+ cons.args << type_name
cons.add_cons(member.name, member.name + '_in')
end
end
@@ -187,7 +187,7 @@
type_class.set_parent("public ::aos::Message")
ts = self.simpleStr()
self.msg_hash = "0x#{Digest::SHA1.hexdigest(ts)[-8..-1]}"
- type_class.add_member("enum {kQueueLength = 200, kHash = #{self.msg_hash}}")
+ type_class.add_member("enum {kQueueLength = 100, kHash = #{self.msg_hash}}")
@members.each do |elem|
type_class.add_member(elem.create_usage(cpp_tree))
end
@@ -245,22 +245,37 @@
def initialize(type,name)
@type,@name = type,name
end
+ def type()
+ return @type
+ end
+ def type_name(cpp_tree)
+ return type()
+ end
def toPrintFormat()
return printformat
end
- def create_usage(cpp_tree)
- "#{@type} #{@name}"
+ def create_usage(cpp_tree, this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ "#{@type} #{this_name}"
end
- def toNetwork(offset,suite, parent = "")
+ def toNetwork(offset,suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
suite << f_call = CPP::FuncCall.build("to_network",
- "&#{parent}#{@name}",
+ "&#{parent}#{this_name}",
"&buffer[#{offset}]")
f_call.args.dont_wrap = true
end
- def toHost(offset,suite, parent = "")
+ def toHost(offset,suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
suite << f_call = CPP::FuncCall.build("to_host",
"&buffer[#{offset}]",
- "&#{parent}#{@name}")
+ "&#{parent}#{this_name}")
f_call.args.dont_wrap = true
end
def getTypeID()
@@ -271,57 +286,112 @@
def simpleStr()
"#{@type} #{@name}"
end
- def set_message_builder(suite)
- suite << "msg_ptr_->#{@name} = #{@name}"
+ def set_message_builder(suite, this_name=nil)
+ this_name ||= @name
+ suite << "msg_ptr_->#{this_name} = #{this_name}"
end
- def zeroCall(suite, parent = "")
- suite << CPP::Assign.new(parent + @name,@zero)
+ def zeroCall(suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ suite << CPP::Assign.new(parent + this_name,@zero)
end
- def fetchPrintArgs(args, parent = "")
- if (self.type == 'bool')
- args.push("#{parent}#{self.name} ? 'T' : 'f'")
- elsif (self.type == '::aos::time::Time')
- args.push("AOS_TIME_ARGS(#{parent}#{self.name}.sec(), #{parent}#{self.name}.nsec())")
+ def fetchPrintArgs(args, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ if (@type == 'bool')
+ args.push("#{parent}#{this_name} ? 'T' : 'f'")
+ elsif (@type == '::aos::time::Time')
+ args.push("AOS_TIME_ARGS(#{parent}#{this_name}.sec(), #{parent}#{this_name}.nsec())")
else
- args.push("#{parent}#{self.name}")
+ args.push("#{parent}#{this_name}")
end
end
end
class Target::MessageArrayElement < Target::Node
- attr_accessor :name,:loc,:size,:zero,:type
- def initialize(type,name,length)
- @type,@name,@length = type,name,length
+ attr_accessor :loc, :length
+ def initialize(type,length)
+ @type,@length = type,length
end
- def create_usage(cpp_tree)
- "#{@type} #{@name}[#@length]"
+ def zero()
+ return @type.zero()
+ end
+ def name()
+ return @type.name()
+ end
+
+ def add_TypeRegister(*args)
+ if @type.respond_to?(:add_TypeRegister)
+ @type.add_TypeRegister(*args)
+ end
+ end
+
+ def toPrintFormat()
+ return ([@type.toPrintFormat] * @length).join(", ")
+ end
+ def create_usage(cpp_tree, this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
+ return "::std::array< #{@type.type_name(cpp_tree)}, #{@length}> #{this_name}"
end
def type()
- "#{@type}[#@length]"
+ return "::std::array< #{@type.type()}, #{@length}>"
+ end
+ def simpleStr()
+ return "#{@type.type} #{@name}[#{@length}]"
+ end
+ def getTypeID()
+ return @type.getTypeID()
end
def size()
- @size * @length
+ return @type.size * @length
end
- def toNetwork(offset,suite)
+ def toNetwork(offset, suite, parent="", this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
offset = (offset == 0) ? "" : "#{offset} + "
- suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
- for_stmt.suite << f_call = CPP::FuncCall.build("to_network",
- "&(#{@name}[i])",
- "&buffer[i + #{offset}::aos::Message::Size()]")
- f_call.args.dont_wrap = true
+ for_loop_var = getForLoopVar()
+ suite << for_stmt = CPP::For.new("int #{for_loop_var} = 0","#{for_loop_var} < #{@length}","#{for_loop_var}++")
+ @type.toNetwork("#{offset} (#{for_loop_var} * #{@type.size})", for_stmt.suite, parent, "#{this_name}[#{for_loop_var}]")
end
- def toHost(offset,suite)
+ def toHost(offset, suite, parent="", this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
offset = (offset == 0) ? "" : "#{offset} + "
- suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
- for_stmt.suite << f_call = CPP::FuncCall.build("to_host",
- "&buffer[i + #{offset}::aos::Message::Size()]",
- "&(#{@name}[i])")
- f_call.args.dont_wrap = true
+ for_loop_var = getForLoopVar()
+ suite << for_stmt = CPP::For.new("int #{for_loop_var} = 0","#{for_loop_var} < #{@length}","#{for_loop_var}++")
+ @type.toHost("#{offset} (#{for_loop_var} * #{@type.size})", for_stmt.suite, parent, "#{this_name}[#{for_loop_var}]")
end
- def set_message_builder(suite)
- suite << "memcpy(msg_ptr_->#{@name},#{@name},#@length)"
+ def set_message_builder(suite, this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
+
+ for_loop_var = getForLoopVar()
+ suite << for_stmt = CPP::For.new("int #{for_loop_var} = 0","#{for_loop_var} < #{@length}","#{for_loop_var}++")
+ @type.set_message_builder(for_stmt.suite, "#{this_name}[#{for_loop_var}]")
end
- def zeroCall(suite)
- suite << "memset(#@name,0,#{size()})"
+ def zeroCall(suite, parent="", this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
+
+ offset = (offset == 0) ? "" : "#{offset} + "
+ for_loop_var = getForLoopVar()
+ suite << for_stmt = CPP::For.new("int #{for_loop_var} = 0","#{for_loop_var} < #{@length}","#{for_loop_var}++")
+ @type.zeroCall(for_stmt.suite, parent, "#{this_name}[#{for_loop_var}]")
+ end
+ def fetchPrintArgs(args, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = name
+ end
+ for i in 0..(@length-1)
+ @type.fetchPrintArgs(args, parent, "#{this_name}[#{i}]")
+ end
end
end
diff --git a/aos/build/queues/output/q_file.rb b/aos/build/queues/output/q_file.rb
index a39799d7..471bdcb 100644
--- a/aos/build/queues/output/q_file.rb
+++ b/aos/build/queues/output/q_file.rb
@@ -4,6 +4,12 @@
require "digest/sha1"
end
+$i = 0
+def getForLoopVar()
+ $i = $i + 1
+ return "_autogen_index_#{$i}"
+end
+
module Target
end
class Target::Node
@@ -30,6 +36,7 @@
end
def make_cpp_tree(rel_path)
cpp_tree = DepFilePair.new(rel_path)
+ cpp_tree.add_header_include("<array>")
cpp_tree.add_header_include("\"aos/common/macros.h\"")
cpp_tree.add_header_include("\"aos/common/queue.h\"")
@class_types.each do |type|
diff --git a/aos/build/queues/output/q_struct.rb b/aos/build/queues/output/q_struct.rb
index 05c2932..7211ff0 100644
--- a/aos/build/queues/output/q_struct.rb
+++ b/aos/build/queues/output/q_struct.rb
@@ -85,29 +85,47 @@
def toPrintFormat()
@type.getPrintFormat()
end
- def create_usage(cpp_tree)
- return "#{type_name(cpp_tree)} #{@name}"
+ def create_usage(cpp_tree, this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ return "#{type_name(cpp_tree)} #{this_name}"
end
def add_TypeRegister(cpp_tree, o_type, member_func)
type = cpp_tree.get(@type)
tName = @type.loc.to_cpp_id(type.name)
member_func.suite << "#{tName}::GetType()"
end
- def fetchPrintArgs(args, parent = "")
- @type.fetchPrintArgs(args, parent + "#{@name}.")
+ def fetchPrintArgs(args, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ @type.fetchPrintArgs(args, parent + "#{this_name}.")
end
- def toNetwork(offset,suite, parent = "")
- @type.toNetwork(offset, suite, parent + "#{@name}.")
+ def toNetwork(offset,suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ @type.toNetwork(offset, suite, parent + "#{this_name}.")
end
- def toHost(offset,suite, parent = "")
- @type.toHost(offset, suite, parent + "#{@name}.")
+ def toHost(offset,suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ @type.toHost(offset, suite, parent + "#{this_name}.")
end
- def set_message_builder(suite)
- suite << "msg_ptr_->#{@name} = #{@name}"
+ def set_message_builder(suite, this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ suite << "msg_ptr_->#{this_name} = #{this_name}"
end
- def zeroCall(suite, parent = "")
- @type.zeroCall(suite, parent + "#{@name}.")
+ def zeroCall(suite, parent = "", this_name=nil)
+ if (this_name == nil)
+ this_name = @name
+ end
+ @type.zeroCall(suite, parent + "#{this_name}.")
end
def simpleStr()
"#{@type.simpleStr()} #{@name}"
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index fb410b7..9a63e48 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -109,6 +109,7 @@
'<(EXTERNALS):gtest',
'test_queue',
'<(AOS)/build/aos.gyp:logging',
+ 'queue_testutils',
],
},
{
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 42dec0c..f04e365 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -43,6 +43,8 @@
for (int i = 0; i < number_fields; ++i) {
to_network(&fields[i]->type, buffer);
buffer += sizeof(fields[i]->type);
+ to_network(&fields[i]->length, buffer);
+ buffer += sizeof(fields[i]->length);
length = fields[i]->name.size();
to_network(&length, buffer);
buffer += sizeof(length);
@@ -53,7 +55,8 @@
return buffer - buffer_start;
}
-MessageType *MessageType::Deserialize(const char *buffer, size_t *bytes) {
+MessageType *MessageType::Deserialize(const char *buffer, size_t *bytes,
+ bool deserialize_length) {
uint16_t name_length;
decltype(MessageType::super_size) super_size;
decltype(MessageType::id) id;
@@ -94,6 +97,10 @@
to_host(buffer, &fields[i]->type);
buffer += sizeof(fields[i]->type);
+ if (deserialize_length) {
+ to_host(buffer, &fields[i]->length);
+ buffer += sizeof(fields[i]->length);
+ }
to_host(buffer, &field_name_length);
buffer += sizeof(field_name_length);
@@ -108,6 +115,50 @@
return r.release();
}
+bool PrintArray(char *output, size_t *output_bytes, const void *input,
+ size_t *input_bytes, uint32_t type_id, uint32_t length) {
+ if (*output_bytes < 1) return false;
+ *output_bytes -= 1;
+ *(output++) = '[';
+
+ bool first = true;
+ for (uint32_t i = 0; i < length; ++i) {
+ if (first) {
+ first = false;
+ } else {
+ if (*output_bytes < 2) return false;
+ *output_bytes -= 2;
+ *(output++) = ',';
+ *(output++) = ' ';
+ }
+
+ const size_t output_bytes_before = *output_bytes,
+ input_bytes_before = *input_bytes;
+ if (MessageType::IsPrimitive(type_id)) {
+ if (!PrintField(output, output_bytes, input, input_bytes, type_id)) {
+ return false;
+ }
+ } else {
+ if (!PrintMessage(output, output_bytes, input, input_bytes,
+ type_cache::Get(type_id))) {
+ return false;
+ }
+ // Ignore the trailing '\0' that the subcall put on.
+ *output_bytes += 1;
+ }
+
+ // Update the input and output pointers.
+ output += output_bytes_before - *output_bytes;
+ input =
+ static_cast<const char *>(input) + input_bytes_before - *input_bytes;
+ }
+ if (*output_bytes < 2) return false;
+ *output_bytes -= 2;
+ *(output++) = ']';
+ *(output++) = '\0';
+ return true;
+}
+
bool PrintMessage(char *output, size_t *output_bytes, const void *input,
size_t *input_bytes, const MessageType &type) {
*input_bytes -= type.super_size;
@@ -138,14 +189,21 @@
const size_t output_bytes_before = *output_bytes,
input_bytes_before = *input_bytes;
- if (MessageType::IsPrimitive(type.fields[i]->type)) {
- if (!PrintField(output, output_bytes, input, input_bytes,
- type.fields[i]->type)) {
+ const uint32_t type_id = type.fields[i]->type;
+ if (type.fields[i]->length > 0) {
+ if (!PrintArray(output, output_bytes, input, input_bytes, type_id,
+ type.fields[i]->length)) {
+ return false;
+ }
+ // Ignore the trailing '\0' that the subcall put on.
+ *output_bytes += 1;
+ } else if (MessageType::IsPrimitive(type_id)) {
+ if (!PrintField(output, output_bytes, input, input_bytes, type_id)) {
return false;
}
} else {
if (!PrintMessage(output, output_bytes, input, input_bytes,
- type_cache::Get(type.fields[i]->type))) {
+ type_cache::Get(type_id))) {
return false;
}
// Ignore the trailing '\0' that the subcall put on.
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index 7381029..be943c1 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -21,6 +21,8 @@
struct Field {
// The type ID for the type of this field.
uint32_t type;
+ // The length of the array if it is one or 0.
+ uint32_t length;
::std::string name;
};
@@ -47,8 +49,11 @@
ssize_t Serialize(char *buffer, size_t max_bytes) const;
// bytes should start out as the number of bytes available in buffer and gets
// reduced by the number actually read before returning.
+ // deserialize_length is whether to look for a length field in the serialized
+ // data.
// Returns a new instance allocated with new or nullptr for error.
- static MessageType *Deserialize(const char *buffer, size_t *bytes);
+ static MessageType *Deserialize(const char *buffer, size_t *bytes,
+ bool deserialize_length = true);
static bool IsPrimitive(uint32_t type_id) {
return (type_id & 0x2000) != 0;
diff --git a/aos/common/queue_types_test.cc b/aos/common/queue_types_test.cc
index 514499b..868820f 100644
--- a/aos/common/queue_types_test.cc
+++ b/aos/common/queue_types_test.cc
@@ -10,10 +10,12 @@
#include "aos/common/byteorder.h"
#include "aos/queue_primitives.h"
#include "aos/common/logging/logging.h"
+#include "aos/common/queue_testutils.h"
using ::aos::common::testing::Structure;
using ::aos::common::testing::MessageWithStructure;
using ::aos::common::testing::OtherTestingMessage;
+using ::aos::common::testing::MessageWithArrays;
namespace aos {
namespace testing {
@@ -21,12 +23,16 @@
typedef MessageType::Field Field;
static const MessageType kTestType1(5, 0x1234, "TestType1",
- {new Field{0, "field1"},
- new Field{0, "field2"},
- new Field{0, "field3"}});
+ {new Field{0, 0, "field1"},
+ new Field{0, 0, "field2"},
+ new Field{0, 0, "field3"}});
class QueueTypesTest : public ::testing::Test {
public:
+ QueueTypesTest() {
+ ::aos::common::testing::EnableTestLogging();
+ }
+
::testing::AssertionResult Equal(const MessageType &l, const MessageType &r) {
using ::testing::AssertionFailure;
if (l.id != r.id) {
@@ -83,7 +89,7 @@
class PrintMessageTest : public ::testing::Test {
public:
- char input[128], output[128];
+ char input[128], output[256];
size_t input_bytes, output_bytes;
};
@@ -194,6 +200,15 @@
static const ::std::string kTestStructure1String =
".aos.common.testing.Structure{struct_bool:f, struct_int:973"
", struct_float:8.560000}";
+static const ::aos::common::testing::Structure kStructureValue(true, 973, 3.14);
+static const MessageWithArrays kTestMessageWithArrays({{971, 254, 1678}},
+ {{kStructureValue,
+ kStructureValue}});
+static const ::std::string kTestMessageWithArraysString =
+ ".aos.common.testing.MessageWithArrays{test_int:[971, 254, 1678], "
+ "test_struct:[.aos.common.testing.Structure{struct_bool:T, struct_int:973, "
+ "struct_float:3.140000}, .aos.common.testing.Structure{struct_bool:T, "
+ "struct_int:973, struct_float:3.140000}]}";
TEST_F(PrintMessageTest, Basic) {
CHECK_GE(sizeof(input), kTestMessage1.Size());
@@ -244,5 +259,16 @@
EXPECT_EQ(kOutput.size() + 1, sizeof(output) - output_bytes);
}
+TEST_F(PrintMessageTest, Array) {
+ CHECK_GE(sizeof(input), kTestMessageWithArrays.Size());
+ input_bytes = kTestMessageWithArrays.Serialize(input);
+ output_bytes = sizeof(output);
+ ASSERT_TRUE(PrintMessage(output, &output_bytes, input, &input_bytes,
+ *kTestMessageWithArrays.GetType()));
+ EXPECT_EQ(kTestMessageWithArraysString, ::std::string(output));
+ EXPECT_EQ(kTestMessageWithArraysString.size() + 1,
+ sizeof(output) - output_bytes);
+}
+
} // namespace testing
} // namespace aos
diff --git a/aos/common/test_queue.q b/aos/common/test_queue.q
index d603802..827b607 100644
--- a/aos/common/test_queue.q
+++ b/aos/common/test_queue.q
@@ -23,6 +23,11 @@
double test_double;
};
+message MessageWithArrays {
+ uint16_t[3] test_int;
+ Structure[2] test_struct;
+};
+
queue TestingMessage test_queue;
queue_group TwoQueues {
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
index 440235d..7da0dc4 100644
--- a/aos/linux_code/logging/log_displayer.cc
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -251,6 +251,13 @@
::aos::MessageType *type = ::aos::MessageType::Deserialize(
reinterpret_cast<const char *>(msg + 1), &bytes);
if (type == nullptr) {
+ LOG(INFO, "Trying old version of type decoding.\n");
+ bytes = msg->message_size;
+ type = ::aos::MessageType::Deserialize(
+ reinterpret_cast<const char *>(msg + 1), &bytes, false);
+ }
+
+ if (type == nullptr) {
LOG(WARNING, "Error deserializing MessageType of size %" PRIx32
" starting at %zx.\n",
msg->message_size, reader.file_offset(msg + 1));