"fields/reserved_field.cc",
"fields/scalar_field.cc",
"fields/size_field.cc",
+ "fields/struct_field.cc",
"checksum_def.cc",
"custom_field_def.cc",
"enum_def.cc",
"enum_gen.cc",
"packet_def.cc",
"parent_def.cc",
+ "struct_def.cc",
"main.cc",
"language_y.yy",
"language_l.ll",
#include "enum_def.h"
#include "enum_gen.h"
#include "packet_def.h"
+#include "struct_def.h"
class Declarations {
public:
#include "fields/reserved_field.h"
#include "fields/scalar_field.h"
#include "fields/size_field.h"
+#include "fields/struct_field.h"
#include "fields/vector_field.h"
} else {
s << "insert(val, i);";
}
+ } else if (IsStructArray()) {
+ s << "val.Serialize(i);";
} else {
s << "insert(val, i, " << element_size_ << ");";
}
bool ArrayField::IsCustomFieldArray() const {
return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
}
+
+bool ArrayField::IsStructArray() const {
+ return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
+}
bool IsCustomFieldArray() const;
+ bool IsStructArray() const;
+
const std::string name_;
const int element_size_{-1}; // in bits
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fields/struct_field.h"
+#include "util.h"
+
+const std::string StructField::kFieldType = "StructField";
+
+StructField::StructField(std::string name, std::string type_name, int size, ParseLocation loc)
+ : PacketField(name, loc), type_name_(type_name), size_(size) {}
+
+const std::string& StructField::GetFieldType() const {
+ return StructField::kFieldType;
+}
+
+Size StructField::GetSize() const {
+ return size_;
+}
+
+Size StructField::GetBuilderSize() const {
+ if (size_ != -1) {
+ return size_;
+ } else {
+ std::string ret = "(" + GetName() + "_.size() * 8) ";
+ return ret;
+ }
+}
+
+std::string StructField::GetDataType() const {
+ return type_name_;
+}
+
+void StructField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << " // start_offset = " << start_offset.ToString() << "\n";
+ s << " // end_offset = " << end_offset.ToString() << "\n";
+}
+
+void StructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ if (size_ != -1) {
+ s << GetDataType();
+ } else {
+ s << "std::vector<" << GetDataType() << ">";
+ }
+ s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+
+ s << "auto it = ";
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ if (start_offset.bits() % 8 != 0) {
+ ERROR(this) << "Struct Field must be byte aligned. start_offset.bits = " << start_offset.bits();
+ }
+ s << "begin() + (" << start_offset << ") / 8;";
+ } else if (size_ != -1) {
+ // If the size of the field is already known, we can determine it's offset based on end().
+ if (!end_offset.empty()) {
+ if (end_offset.bits() % 8) {
+ ERROR(this) << "Struct Field must be byte aligned. end_offset.bits = " << end_offset.bits();
+ }
+
+ s << "end() - (" << size_ << " + " << end_offset << ") / 8;";
+ } else {
+ ERROR(this) << "Ambiguous offset for fixed size custom field.";
+ }
+ } else {
+ ERROR(this) << "Struct Field offset can not be determined from begin().";
+ }
+
+ s << "std::vector<" << GetDataType() << "> to_return;";
+ s << GetDataType() << "::Parse(to_return, it);";
+ if (size_ != -1) {
+ s << "return to_return[0];";
+ } else {
+ s << "return to_return;";
+ }
+ s << "}\n";
+}
+
+bool StructField::GenBuilderParameter(std::ostream& s) const {
+ s << GetDataType() << " " << GetName();
+ return true;
+}
+
+bool StructField::HasParameterValidator() const {
+ return false;
+}
+
+void StructField::GenParameterValidator(std::ostream&) const {
+ // Validated at compile time.
+}
+
+void StructField::GenInserter(std::ostream& s) const {
+ s << GetName() << "_.Serialize(i);";
+}
+
+void StructField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class StructField : public PacketField {
+ public:
+ StructField(std::string name, std::string type_name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+
+ public:
+ const int size_{-1};
+};
return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_) + ")";
}
- if (IsCustomFieldArray()) {
+ if (IsCustomFieldArray() || IsStructArray()) {
if (type_def_->size_ != -1) {
return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_) +
")";
} else {
s << "insert(val, i);";
}
+ } else if (IsStructArray()) {
+ s << "val.Serialize(i);";
} else {
s << "insert(val, i, " << element_size_ << ");";
}
return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
}
+bool VectorField::IsStructArray() const {
+ return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
+}
+
void VectorField::SetSizeField(const SizeField* size_field) {
if (size_field->GetFieldType() == CountField::kFieldType && !size_modifier_.empty()) {
ERROR(this, size_field) << "Can not use count field to describe array with a size modifier."
bool IsCustomFieldArray() const;
+ bool IsStructArray() const;
+
void SetSizeField(const SizeField* size_field);
const std::string& GetSizeModifier() const;
"enum" { return(token::ENUM); }
"group" { return(token::GROUP); }
"packet" { return(token::PACKET); }
+"struct" { return(token::STRUCT); }
"little_endian_packets" {
yylval->integer = 1;
return token::IS_LITTLE_ENDIAN;
FieldList* packet_field_definitions;
PacketField* packet_field_type;
+ StructDef* struct_definition_value;
+
std::map<std::string, std::variant<int64_t, std::string>>* constraint_list_t;
std::pair<std::string, std::variant<int64_t, std::string>>* constraint_t;
}
%token PACKET "packet"
%token PAYLOAD "payload"
%token BODY "body"
+%token STRUCT "struct"
%token SIZE "size"
%token COUNT "count"
%token FIXED "fixed"
%type<packet_field_type> reserved_field_definition;
%type<packet_field_type> array_field_definition;
+%type<struct_definition_value> struct_definition;
+
%type<constraint_list_t> constraint_list;
%type<constraint_t> constraint;
%destructor { std::cout << "DESTROYING STRING " << *$$ << "\n"; delete $$; } IDENTIFIER STRING SIZE_MODIFIER
decls->AddPacketDef($1->name_, std::move(*$1));
delete $1;
}
+ | struct_definition
+ {
+ std::cerr << "FOUND STRUCT\n\n";
+ decls->AddTypeDef($1->name_, $1);
+ }
| group_definition
{
// All actions are handled in group_definition
delete $3;
}
+struct_definition
+ : STRUCT IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& field_definition_list = *$4;
+
+ DEBUG() << "Struct " << struct_name << " with no parent";
+ DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size();
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list));
+ struct_definition->AssignSizeFields();
+
+ $$ = struct_definition;
+ delete $2;
+ delete $4;
+ }
+ | STRUCT IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& parent_struct_name = *$4;
+ auto&& field_definition_list = *$6;
+
+ std::cerr << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
+ std::cerr << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+
+ auto parent_struct = decls->GetTypeDef(parent_struct_name);
+ if (parent_struct == nullptr) {
+ ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+ << " used as parent for " << struct_name;
+ }
+
+ if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+ ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+ }
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+ struct_definition->AssignSizeFields();
+
+ $$ = struct_definition;
+ delete $2;
+ delete $4;
+ delete $6;
+ }
+ | STRUCT IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& parent_struct_name = *$4;
+ auto&& constraints = *$6;
+ auto&& field_definition_list = *$9;
+
+ auto parent_struct = decls->GetTypeDef(parent_struct_name);
+ if (parent_struct == nullptr) {
+ ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+ << " used as parent for " << struct_name;
+ }
+
+ if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+ ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+ }
+
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+ struct_definition->AssignSizeFields();
+
+ for (const auto& constraint : constraints) {
+ const auto& constraint_name = constraint.first;
+ const auto& constraint_value = constraint.second;
+ DEBUG() << "Parent constraint on " << constraint_name;
+ struct_definition->AddParentConstraint(constraint_name, constraint_value);
+ }
+
+ $$ = struct_definition;
+
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $9;
+ }
+
packet_definition
: PACKET IDENTIFIER '{' field_definition_list '}' /* Packet with no parent */
{
out_file << "#include \"os/log.h\"\n";
out_file << "#include \"packet/base_packet_builder.h\"\n";
out_file << "#include \"packet/bit_inserter.h\"\n";
+ out_file << "#include \"packet/iterator.h\"\n";
out_file << "#include \"packet/packet_builder.h\"\n";
+ out_file << "#include \"packet/packet_struct.h\"\n";
out_file << "#include \"packet/packet_view.h\"\n";
out_file << "#include \"packet/parser/checksum_type_checker.h\"\n";
out_file << "#include \"packet/parser/custom_type_checker.h\"\n";
out_file << "using ::bluetooth::packet::BasePacketBuilder;";
out_file << "using ::bluetooth::packet::BitInserter;";
out_file << "using ::bluetooth::packet::CustomTypeChecker;";
+ out_file << "using ::bluetooth::packet::Iterator;";
out_file << "using ::bluetooth::packet::kLittleEndian;";
out_file << "using ::bluetooth::packet::PacketBuilder;";
+ out_file << "using ::bluetooth::packet::PacketStruct;";
out_file << "using ::bluetooth::packet::PacketView;";
out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
out_file << "\n\n";
}
out_file << "\n";
+ for (auto& s : decls.type_defs_queue_) {
+ if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ ((StructDef*)s.second)->SetEndianness(decls.is_little_endian);
+ ((StructDef*)s.second)->GenDefinition(out_file);
+ out_file << "\n";
+ }
+ }
+
for (size_t i = 0; i < decls.packet_defs_queue_.size(); i++) {
decls.packet_defs_queue_[i].second.SetEndianness(decls.is_little_endian);
decls.packet_defs_queue_[i].second.GenParserDefinition(out_file);
FieldList params;
std::set<std::string> param_types = {
- ScalarField::kFieldType, EnumField::kFieldType, ArrayField::kFieldType,
- VectorField::kFieldType, CustomField::kFieldType, PayloadField::kFieldType,
+ ScalarField::kFieldType, EnumField::kFieldType, ArrayField::kFieldType, VectorField::kFieldType,
+ CustomField::kFieldType, StructField::kFieldType, PayloadField::kFieldType,
};
if (parent_ != nullptr) {
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "struct_def.h"
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+StructDef::StructDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr){};
+StructDef::StructDef(std::string name, FieldList fields, StructDef* parent) : ParentDef(name, fields, parent){};
+
+PacketField* StructDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ Size total_size = GetSize(false);
+ if (fields_.HasBody()) {
+ ERROR(new StructField(name, name_, -1, loc)) << "Variable size structs are not supported";
+ fprintf(stderr, "total_size of %s(%s) = %s\n", name_.c_str(), name.c_str(), total_size.ToString().c_str());
+ abort();
+ return new StructField(name, name_, -1, loc);
+ } else {
+ return new StructField(name, name_, total_size.bits(), loc);
+ }
+}
+
+TypeDef::Type StructDef::GetDefinitionType() const {
+ return TypeDef::Type::STRUCT;
+}
+
+void StructDef::GenParse(std::ostream& s) const {
+ if (is_little_endian_) {
+ s << "static Iterator<kLittleEndian> Parse(std::vector<" << name_ << ">& vec, Iterator<kLittleEndian> it) {";
+ } else {
+ s << "static Iterator<!kLittleEndian> Parse(std::vector<" << name_ << ">& vec, Iterator<!kLittleEndian> it) {";
+ }
+ s << "auto begin_it = it;";
+ s << name_ << " one;";
+ if (parent_ != nullptr) {
+ s << "begin_it += one." << parent_->name_ << "::BitsOfHeader() / 8;";
+ }
+ Size field_offset = Size(0);
+ for (const auto& field : fields_) {
+ // TODO: DON'T commit this logging
+ s << "\n/* (before adding) field_offset " << field_offset.bits() << " */\n ";
+ s << "\n/* (before adding) field->GetSize() " << field->GetSize().bits() << " */\n ";
+ // Size next_field_offset = field_offset + field->GetSize();
+ Size next_field_offset = field->GetSize() + field_offset.bits();
+ s << "\n/* field_offset " << field_offset.bits() << " */\n ";
+ if (field->GetFieldType() != ReservedField::kFieldType && field->GetFieldType() != BodyField::kFieldType &&
+ field->GetFieldType() != FixedScalarField::kFieldType && field->GetFieldType() != SizeField::kFieldType &&
+ field->GetFieldType() != CountField::kFieldType) {
+ s << "{";
+ field->GenExtractor(s, field_offset, next_field_offset);
+ s << "one." << field->GetName() << "_ = value;";
+ s << "}";
+ }
+ field_offset = next_field_offset;
+ }
+ s << "vec.push_back(one);";
+ s << "return it + " << field_offset.bytes() << ";";
+ s << "}";
+}
+
+void StructDef::GenDefinition(std::ostream& s) const {
+ s << "class " << name_;
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_;
+ } else {
+ if (is_little_endian_) {
+ s << " : public PacketStruct<kLittleEndian>";
+ } else {
+ s << " : public PacketStruct<!kLittleEndian>";
+ }
+ }
+ s << " {";
+ s << " public:";
+
+ GenConstructor(s);
+
+ std::set<std::string> fixed_types = {
+ FixedScalarField::kFieldType,
+ FixedEnumField::kFieldType,
+ };
+
+ // Print all of the public fields which are all the fields minus the fixed fields.
+ const auto& public_fields = fields_.GetFieldsWithoutTypes(fixed_types);
+ bool has_fixed_fields = public_fields.size() != fields_.size();
+ for (const auto& field : public_fields) {
+ // GenParserFieldGetter(s, field);
+ s << "/*FieldGetter for " << field->GetName() << "*/\n";
+ s << "\n";
+ }
+
+ // Print the private fields which are the fixed fields.
+ if (has_fixed_fields) {
+ const auto& private_fields = fields_.GetFieldsWithTypes(fixed_types);
+ s << "/* private: */\n";
+ for (const auto& field : private_fields) {
+ // GenParserFieldGetter(s, field);
+ s << "/* FieldGetter for " << field->GetName() << "*/\n";
+ }
+ }
+ s << " public:\n";
+ s << " virtual ~" << name_ << "() override = default;\n";
+
+ GenSerialize(s);
+ s << "\n";
+
+ GenParse(s);
+ s << "\n";
+
+ GenSize(s);
+ s << "\n";
+
+ GenMembers(s);
+ s << "};\n";
+}
+
+void StructDef::GenConstructor(std::ostream& s) const {
+ if (parent_ != nullptr) {
+ s << name_ << "() : " << parent_->name_ << "() {";
+ } else {
+ s << name_ << "() {";
+ }
+
+ // Get the list of parent params.
+ FieldList parent_params;
+ if (parent_ != nullptr) {
+ parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+
+ // Set constrained parent fields to their correct values.
+ for (int i = 0; i < parent_params.size(); i++) {
+ const auto& field = parent_params[i];
+ const auto& constraint = parent_constraints_.find(field->GetName());
+ if (constraint != parent_constraints_.end()) {
+ s << parent_->name_ << "::" << field->GetName() << "_ = ";
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ s << std::get<int64_t>(constraint->second) << ";";
+ } else if (field->GetFieldType() == EnumField::kFieldType) {
+ s << std::get<std::string>(constraint->second) << ";";
+ } else {
+ ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+ }
+ }
+ }
+ }
+
+ /*
+ // Build a list of parameters that excludes all parent parameters.
+ FieldList saved_params;
+ for (const auto& field : params) {
+ if (parent_params.GetField(field->GetName()) == nullptr) {
+ saved_params.AppendField(field);
+ }
+ }
+ if (parent_ != nullptr && saved_params.size() > 0) {
+ s << ",";
+ }
+ for (int i = 0; i < saved_params.size(); i++) {
+ const auto& saved_param_name = saved_params[i]->GetName();
+ s << saved_param_name << "_(" << saved_param_name << ")";
+ if (i != saved_params.size() - 1) {
+ s << ",";
+ }
+ }
+ s << " {";
+
+ */
+ s << "}\n";
+}
--- /dev/null
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <variant>
+
+#include "enum_def.h"
+#include "field_list.h"
+#include "fields/all_fields.h"
+#include "fields/packet_field.h"
+#include "parent_def.h"
+#include "parse_location.h"
+
+class StructDef : public ParentDef {
+ public:
+ StructDef(std::string name, FieldList fields);
+ StructDef(std::string name, FieldList fields, StructDef* parent);
+
+ PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+ TypeDef::Type GetDefinitionType() const;
+
+ void GenParse(std::ostream& s) const;
+
+ void GenDefinition(std::ostream& s) const;
+
+ void GenConstructor(std::ostream& s) const;
+};
ASSERT_EQ(array[i].data, count_array[i].data);
}
}
+
+vector<uint8_t> one_struct{
+ 0x01, 0x02, 0x03, // id = 0x01, count = 0x0302
+};
+
+TEST(GeneratedPacketTest, testOneStruct) {
+ TwoRelatedNumbers trn;
+ trn.id_ = 1;
+ trn.count_ = 0x0302;
+
+ auto packet = OneStructBuilder::Create(trn);
+ ASSERT_EQ(one_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_struct.size(); i++) {
+ ASSERT_EQ(one_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, trn.id_);
+ ASSERT_EQ(one.count_, trn.count_);
+}
+
+vector<uint8_t> two_structs{
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04,
+};
+
+TEST(GeneratedPacketTest, testTwoStructs) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 3; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+
+ auto packet = TwoStructsBuilder::Create(count_array[0], count_array[1]);
+ ASSERT_EQ(two_structs.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(two_structs.size(), packet_bytes->size());
+ for (size_t i = 0; i < two_structs.size(); i++) {
+ ASSERT_EQ(two_structs[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = TwoStructsView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, count_array[0].id_);
+ ASSERT_EQ(one.count_, count_array[0].count_);
+ auto two = view.GetTwo();
+ ASSERT_EQ(two.id_, count_array[1].id_);
+ ASSERT_EQ(two.count_, count_array[1].count_);
+}
+
+vector<uint8_t> array_of_struct{
+ 0x04, // _count_
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
+};
+
+TEST(GeneratedPacketTest, testArrayOfStruct) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+
+ auto packet = ArrayOfStructBuilder::Create(count_array);
+ ASSERT_EQ(array_of_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_of_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_of_struct.size(); i++) {
+ ASSERT_EQ(array_of_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ArrayOfStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, count_array[i].id_);
+ ASSERT_EQ(array[i].count_, count_array[i].count_);
+ }
+}
+
+vector<uint8_t> array_of_struct_and_another{
+ 0x03, // _count_
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04, // 2
+ 0x03, 0x03, 0x06, // 3
+ 0x04, 0x04, 0x08, // Another
+};
+
+TEST(GeneratedPacketTest, testArrayOfStructAndAnother) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 4; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+ TwoRelatedNumbers another;
+ another.id_ = 4;
+ another.count_ = 0x0201 * 4;
+
+ auto packet = ArrayOfStructAndAnotherBuilder::Create(count_array, another);
+ ASSERT_EQ(array_of_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_of_struct_and_another.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_of_struct_and_another.size(); i++) {
+ ASSERT_EQ(array_of_struct_and_another[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ArrayOfStructAndAnotherView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, count_array[i].id_);
+ ASSERT_EQ(array[i].count_, count_array[i].count_);
+ }
+ auto nother = view.GetAnother();
+ ASSERT_EQ(nother.id_, another.id_);
+ ASSERT_EQ(nother.count_, another.count_);
+}
+
+vector<uint8_t> bit_field_group_packet{
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupPacket) {
+ uint8_t seven_bits = 0x77;
+ uint8_t straddle = 0x5;
+ uint8_t five_bits = 0x15;
+
+ auto packet = BitFieldGroupPacketBuilder::Create(seven_bits, straddle, five_bits);
+ ASSERT_EQ(bit_field_group_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_group_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_group_packet.size(); i++) {
+ ASSERT_EQ(bit_field_group_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldGroupPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(seven_bits, view.GetSevenBits());
+ ASSERT_EQ(straddle, view.GetStraddle());
+ ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_packet{
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldPacket) {
+ BitField bit_field;
+ bit_field.seven_bits_ = 0x77;
+ bit_field.straddle_ = 0x5;
+ bit_field.five_bits_ = 0x15;
+
+ auto packet = BitFieldPacketBuilder::Create(bit_field);
+ ASSERT_EQ(bit_field_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_packet.size(); i++) {
+ ASSERT_EQ(bit_field_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ BitField bf = view.GetBitField();
+ ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_group_after_unsized_array_packet{
+ 0x01, 0x02, 0x03, 0x04, // byte array
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupAfterUnsizedArrayPacket) {
+ std::vector<uint8_t> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ count_array.push_back(i);
+ }
+ uint8_t seven_bits = 0x77;
+ uint8_t straddle = 0x5;
+ uint8_t five_bits = 0x15;
+
+ auto packet = BitFieldGroupAfterUnsizedArrayPacketBuilder::Create(count_array, seven_bits, straddle, five_bits);
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_group_after_unsized_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto payload_view = BitFieldGroupAfterPayloadPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(payload_view.IsValid());
+ EXPECT_EQ(seven_bits, payload_view.GetSevenBits());
+ EXPECT_EQ(straddle, payload_view.GetStraddle());
+ EXPECT_EQ(five_bits, payload_view.GetFiveBits());
+
+ auto view = BitFieldGroupAfterUnsizedArrayPacketView::Create(payload_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+ ASSERT_EQ(seven_bits, view.GetSevenBits());
+ ASSERT_EQ(straddle, view.GetStraddle());
+ ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_after_unsized_array_packet{
+ 0x01, 0x02, 0x03, 0x04, // byte array
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldAfterUnsizedArrayPacket) {
+ std::vector<uint8_t> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ count_array.push_back(i);
+ }
+ BitField bit_field;
+ bit_field.seven_bits_ = 0x77;
+ bit_field.straddle_ = 0x5;
+ bit_field.five_bits_ = 0x15;
+
+ auto packet = BitFieldAfterUnsizedArrayPacketBuilder::Create(count_array, bit_field);
+ ASSERT_EQ(bit_field_after_unsized_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_after_unsized_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_after_unsized_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_after_unsized_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto payload_view = BitFieldAfterPayloadPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(payload_view.IsValid());
+ BitField parent_bf = payload_view.GetBitField();
+ ASSERT_EQ(parent_bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(parent_bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(parent_bf.five_bits_, bit_field.five_bits_);
+
+ auto view = BitFieldAfterUnsizedArrayPacketView::Create(payload_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+ BitField bf = view.GetBitField();
+ ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_array_packet{
+ 0x06, // _size_(array)
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+
+ // seven_bits_ = 0x78, straddle_ = 0x6, five_bits_ = 0x16
+ 0x78, // 0x78 | (0x6 & 0x1) << 7
+ 0xb3, // 0x16 << 3 | (0x6 >> 1)
+
+ // seven_bits_ = 0x79, straddle_ = 0x7, five_bits_ = 0x17
+ 0xf9, // 0x79 | (0x7 & 0x1) << 7
+ 0xbb, // 0x17 << 3 | (0x7 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldArrayPacket) {
+ std::vector<BitField> count_array;
+ for (size_t i = 0; i < 3; i++) {
+ BitField bf;
+ bf.seven_bits_ = 0x77 + i;
+ bf.straddle_ = 0x5 + i;
+ bf.five_bits_ = 0x15 + i;
+ count_array.push_back(bf);
+ }
+
+ auto packet = BitFieldArrayPacketBuilder::Create(count_array);
+ ASSERT_EQ(bit_field_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldArrayPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].seven_bits_, count_array[i].seven_bits_);
+ ASSERT_EQ(array[i].straddle_, count_array[i].straddle_);
+ ASSERT_EQ(array[i].five_bits_, count_array[i].five_bits_);
+ }
+}
+
} // namespace parser
} // namespace packet
} // namespace bluetooth
_count_(variable_array) : 8,
variable_array : Variable[],
}
+
+struct TwoRelatedNumbers {
+ id : 8,
+ count : 16,
+}
+
+packet OneStruct {
+ one : TwoRelatedNumbers,
+}
+
+packet TwoStructs {
+ one : TwoRelatedNumbers,
+ two : TwoRelatedNumbers,
+}
+
+packet ArrayOfStruct {
+ _count_(array) : 8,
+ array : TwoRelatedNumbers[],
+}
+
+packet ArrayOfStructAndAnother {
+ _count_(array) : 8,
+ array : TwoRelatedNumbers[],
+ another : TwoRelatedNumbers,
+}
+
+group BitFieldGroup {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldGroupPacket {
+ BitFieldGroup,
+}
+
+packet BitFieldGroupAfterPayloadPacket {
+ _payload_,
+ BitFieldGroup,
+}
+
+packet BitFieldGroupAfterUnsizedArrayPacket : BitFieldGroupAfterPayloadPacket {
+ array : 8[],
+}
+
+struct BitField {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldPacket {
+ bit_field : BitField,
+}
+
+packet BitFieldAfterPayloadPacket {
+ _payload_,
+ bit_field : BitField,
+}
+
+packet BitFieldAfterUnsizedArrayPacket : BitFieldAfterPayloadPacket {
+ array : 8[],
+}
+
+packet BitFieldArrayPacket {
+ _size_(array): 8,
+ array : BitField[],
+}
CHECKSUM,
CUSTOM,
PACKET,
+ STRUCT,
};
virtual Type GetDefinitionType() const = 0;