X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=generator%2Fnanopb_generator.py;h=9cce6a5a27a739466f18dc411f8d40a829f2497b;hb=07375a126337916f3a34ea94f8085b8f89d789a1;hp=2f1d92f48df3ea6dc76a5173169f2efe248ca8fb;hpb=eb0e73ca53e09f2ba42cd9775168b683c98b84ea;p=apps%2Fagl-service-can-low-level.git diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index 2f1d92f4..9cce6a5a 100755 --- a/generator/nanopb_generator.py +++ b/generator/nanopb_generator.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' -nanopb_version = "nanopb-0.3.6" +nanopb_version = "nanopb-0.3.8-dev" import sys import re @@ -207,6 +207,27 @@ class Enum: for i, x in enumerate(self.values): result += '\n#define %s %s' % (self.value_longnames[i], x[0]) + if self.options.enum_to_string: + result += '\nconst char *%s_name(%s v);\n' % (self.names, self.names) + + return result + + def enum_to_string_definition(self): + if not self.options.enum_to_string: + return "" + + result = 'const char *%s_name(%s v) {\n' % (self.names, self.names) + result += ' switch (v) {\n' + + for ((enumname, _), strname) in zip(self.values, self.value_longnames): + # Strip off the leading type name from the string value. + strval = str(strname)[len(str(self.names)) + 1:] + result += ' case %s: return "%s";\n' % (enumname, strval) + + result += ' }\n' + result += ' return "unknown";\n' + result += '}\n' + return result class FieldMaxSize: @@ -241,9 +262,20 @@ class Field: self.enc_size = None self.ctype = None + if field_options.type == nanopb_pb2.FT_INLINE: + # Before nanopb-0.3.8, fixed length bytes arrays were specified + # by setting type to FT_INLINE. But to handle pointer typed fields, + # it makes sense to have it as a separate option. + field_options.type = nanopb_pb2.FT_STATIC + field_options.fixed_length = True + # Parse field options if field_options.HasField("max_size"): self.max_size = field_options.max_size + + if desc.type == FieldD.TYPE_STRING and field_options.HasField("max_length"): + # max_length overrides max_size for strings + self.max_size = field_options.max_length + 1 if field_options.HasField("max_count"): self.max_count = field_options.max_count @@ -253,16 +285,18 @@ class Field: # Check field rules, i.e. required/optional/repeated. can_be_static = True - if desc.label == FieldD.LABEL_REQUIRED: - self.rules = 'REQUIRED' - elif desc.label == FieldD.LABEL_OPTIONAL: - self.rules = 'OPTIONAL' - elif desc.label == FieldD.LABEL_REPEATED: + if desc.label == FieldD.LABEL_REPEATED: self.rules = 'REPEATED' if self.max_count is None: can_be_static = False else: self.array_decl = '[%d]' % self.max_count + elif field_options.proto3: + self.rules = 'SINGULAR' + elif desc.label == FieldD.LABEL_REQUIRED: + self.rules = 'REQUIRED' + elif desc.label == FieldD.LABEL_OPTIONAL: + self.rules = 'OPTIONAL' else: raise NotImplementedError(desc.label) @@ -317,12 +351,17 @@ class Field: self.array_decl += '[%d]' % self.max_size self.enc_size = varint_max_size(self.max_size) + self.max_size elif desc.type == FieldD.TYPE_BYTES: - self.pbtype = 'BYTES' - if self.allocation == 'STATIC': - self.ctype = self.struct_name + self.name + 't' + if field_options.fixed_length: + self.pbtype = 'FIXED_LENGTH_BYTES' self.enc_size = varint_max_size(self.max_size) + self.max_size - elif self.allocation == 'POINTER': + self.ctype = 'pb_byte_t' + self.array_decl += '[%d]' % self.max_size + else: + self.pbtype = 'BYTES' self.ctype = 'pb_bytes_array_t' + if self.allocation == 'STATIC': + self.ctype = self.struct_name + self.name + 't' + self.enc_size = varint_max_size(self.max_size) + self.max_size elif desc.type == FieldD.TYPE_MESSAGE: self.pbtype = 'MESSAGE' self.ctype = self.submsgname = names_from_type_name(desc.type_name) @@ -342,6 +381,9 @@ class Field: if self.pbtype == 'MESSAGE': # Use struct definition, so recursive submessages are possible result += ' struct _%s *%s;' % (self.ctype, self.name) + elif self.pbtype == 'FIXED_LENGTH_BYTES': + # Pointer to fixed size array + result += ' %s (*%s)%s;' % (self.ctype, self.name, self.array_decl) elif self.rules == 'REPEATED' and self.pbtype in ['STRING', 'BYTES']: # String/bytes arrays need to be defined as pointers to pointers result += ' %s **%s;' % (self.ctype, self.name) @@ -389,6 +431,8 @@ class Field: inner_init = '""' elif self.pbtype == 'BYTES': inner_init = '{0, {0}}' + elif self.pbtype == 'FIXED_LENGTH_BYTES': + inner_init = '{0}' elif self.pbtype in ('ENUM', 'UENUM'): inner_init = '(%s)0' % self.ctype else: @@ -403,6 +447,12 @@ class Field: inner_init = '{0, {0}}' else: inner_init = '{%d, {%s}}' % (len(data), ','.join(data)) + elif self.pbtype == 'FIXED_LENGTH_BYTES': + data = ['0x%02x' % ord(c) for c in self.default] + if len(data) == 0: + inner_init = '{0}' + else: + inner_init = '{%s}' % ','.join(data) elif self.pbtype in ['FIXED32', 'UINT32']: inner_init = str(self.default) + 'u' elif self.pbtype in ['FIXED64', 'UINT64']: @@ -454,6 +504,10 @@ class Field: elif self.pbtype == 'BYTES': if self.allocation != 'STATIC': return None # Not implemented + elif self.pbtype == 'FIXED_LENGTH_BYTES': + if self.allocation != 'STATIC': + return None # Not implemented + array_decl = '[%d]' % self.max_size if declaration_only: return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl) @@ -465,9 +519,10 @@ class Field: identifier = '%s_%s_tag' % (self.struct_name, self.name) return '#define %-40s %d\n' % (identifier, self.tag) - def pb_field_t(self, prev_field_name): + def pb_field_t(self, prev_field_name, union_index = None): '''Return the pb_field_t initializer to use in the constant array. - prev_field_name is the name of the previous field or None. + prev_field_name is the name of the previous field or None. For OneOf + unions, union_index is the index of this field inside the OneOf. ''' if self.rules == 'ONEOF': @@ -482,7 +537,14 @@ class Field: result += '%-8s, ' % self.pbtype result += '%s, ' % self.rules result += '%-8s, ' % self.allocation - result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER") + + if union_index is not None and union_index > 0: + result += 'UNION, ' + elif prev_field_name is None: + result += 'FIRST, ' + else: + result += 'OTHER, ' + result += '%s, ' % self.struct_name result += '%s, ' % self.name result += '%s, ' % (prev_field_name or self.name) @@ -491,7 +553,7 @@ class Field: result += '&%s_fields)' % self.submsgname elif self.default is None: result += '0)' - elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC': + elif self.pbtype in ['BYTES', 'STRING', 'FIXED_LENGTH_BYTES'] and self.allocation != 'STATIC': result += '0)' # Arbitrary size default values not implemented elif self.rules == 'OPTEXT': result += '0)' # Default value for extensions is not implemented @@ -507,8 +569,8 @@ class Field: '''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly. Returns numeric value or a C-expression for assert.''' check = [] - if self.pbtype == 'MESSAGE': - if self.rules == 'REPEATED' and self.allocation == 'STATIC': + if self.pbtype == 'MESSAGE' and self.allocation == 'STATIC': + if self.rules == 'REPEATED': check.append('pb_membersize(%s, %s[0])' % (self.struct_name, self.name)) elif self.rules == 'ONEOF': if self.anonymous: @@ -517,6 +579,9 @@ class Field: check.append('pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name)) else: check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name)) + elif self.pbtype == 'BYTES' and self.allocation == 'STATIC': + if self.max_size > 251: + check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name)) return FieldMaxSize([self.tag, self.max_size, self.max_count], check, @@ -718,8 +783,10 @@ class OneOf(Field): return ''.join([f.tags() for f in self.fields]) def pb_field_t(self, prev_field_name): - result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields]) - return result + parts = [] + for union_index, field in enumerate(self.fields): + parts.append(field.pb_field_t(prev_field_name, union_index)) + return ',\n'.join(parts) def get_last_field_name(self): if self.anonymous: @@ -1045,7 +1112,10 @@ class ProtoFile: else: yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) - symbol = make_identifier(headername) + if self.fdesc.package: + symbol = make_identifier(self.fdesc.package + '_' + headername) + else: + symbol = make_identifier(headername) yield '#ifndef PB_%s_INCLUDED\n' % symbol yield '#define PB_%s_INCLUDED\n' % symbol try: @@ -1189,6 +1259,9 @@ class ProtoFile: for ext in self.extensions: yield ext.extension_def() + '\n' + for enum in self.enums: + yield enum.enum_to_string_definition() + '\n' + # Add checks for numeric limits if self.messages: largest_msg = max(self.messages, key = lambda m: m.count_required_fields()) @@ -1318,6 +1391,9 @@ def get_nanopb_suboptions(subdesc, options, name): new_options = nanopb_pb2.NanoPBOptions() new_options.CopyFrom(options) + if hasattr(subdesc, 'syntax') and subdesc.syntax == "proto3": + new_options.proto3 = True + # Handle options defined in a separate file dotname = '.'.join(name.parts) for namemask, options in Globals.separate_options: