X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=generator%2Fnanopb_generator.py;h=b9cfcc3de4e0da4e138d40b226c421ef76883023;hb=b947dc6e2c0d63a29e83ebf9c8af450d2531aef2;hp=c73718871307093b9cf1662a967491a7cf7ea8d7;hpb=7f97ad549e8ef2050c662b8160745402e84e8006;p=apps%2Fagl-service-can-low-level.git diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index c7371887..b9cfcc3d 100755 --- a/generator/nanopb_generator.py +++ b/generator/nanopb_generator.py @@ -1,7 +1,7 @@ #!/usr/bin/python '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' -nanopb_version = "nanopb-0.2.9-dev" +nanopb_version = "nanopb-0.3.1" import sys @@ -261,7 +261,7 @@ class Field: result = '' if self.allocation == 'POINTER': if self.rules == 'REPEATED': - result += ' size_t ' + self.name + '_count;\n' + result += ' pb_size_t ' + self.name + '_count;\n' if self.pbtype == 'MESSAGE': # Use struct definition, so recursive submessages are possible @@ -277,50 +277,75 @@ class Field: if self.rules == 'OPTIONAL' and self.allocation == 'STATIC': result += ' bool has_' + self.name + ';\n' elif self.rules == 'REPEATED' and self.allocation == 'STATIC': - result += ' size_t ' + self.name + '_count;\n' + result += ' pb_size_t ' + self.name + '_count;\n' result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl) return result def types(self): '''Return definitions for any special types this field might need.''' if self.pbtype == 'BYTES' and self.allocation == 'STATIC': - result = 'typedef struct {\n' - result += ' size_t size;\n' - result += ' uint8_t bytes[%d];\n' % self.max_size - result += '} %s;\n' % self.ctype + result = 'typedef PB_BYTES_ARRAY_T(%d) %s;\n' % (self.max_size, self.ctype) else: result = None return result + def get_initializer(self, null_init): + '''Return literal expression for this field's default value.''' + + if self.pbtype == 'MESSAGE': + if null_init: + return '%s_init_zero' % self.ctype + else: + return '%s_init_default' % self.ctype + + if self.default is None or null_init: + if self.pbtype == 'STRING': + return '""' + elif self.pbtype == 'BYTES': + return '{0, {0}}' + elif self.pbtype == 'ENUM': + return '(%s)0' % self.ctype + else: + return '0' + + default = str(self.default) + + if self.pbtype == 'STRING': + default = default.encode('utf-8').encode('string_escape') + default = default.replace('"', '\\"') + default = '"' + default + '"' + elif self.pbtype == 'BYTES': + data = default.decode('string_escape') + data = ['0x%02x' % ord(c) for c in data] + if len(data) == 0: + default = '{0, {0}}' + else: + default = '{%d, {%s}}' % (len(data), ','.join(data)) + elif self.pbtype in ['FIXED32', 'UINT32']: + default += 'u' + elif self.pbtype in ['FIXED64', 'UINT64']: + default += 'ull' + elif self.pbtype in ['SFIXED64', 'INT64']: + default += 'll' + + return default + def default_decl(self, declaration_only = False): '''Return definition for this field's default value.''' if self.default is None: return None - ctype, default = self.ctype, self.default + ctype = self.ctype + default = self.get_initializer(False) array_decl = '' if self.pbtype == 'STRING': if self.allocation != 'STATIC': return None # Not implemented - array_decl = '[%d]' % self.max_size - default = str(self.default).encode('string_escape') - default = default.replace('"', '\\"') - default = '"' + default + '"' elif self.pbtype == 'BYTES': if self.allocation != 'STATIC': return None # Not implemented - - data = self.default.decode('string_escape') - data = ['0x%02x' % ord(c) for c in data] - default = '{%d, {%s}}' % (len(data), ','.join(data)) - elif self.pbtype in ['FIXED32', 'UINT32']: - default += 'u' - elif self.pbtype in ['FIXED64', 'UINT64']: - default += 'ull' - elif self.pbtype in ['SFIXED64', 'INT64']: - default += 'll' if declaration_only: return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl) @@ -336,7 +361,7 @@ class Field: '''Return the pb_field_t initializer to use in the constant array. prev_field_name is the name of the previous field or None. ''' - result = ' PB_FIELD2(%3d, ' % self.tag + result = ' PB_FIELD(%3d, ' % self.tag result += '%-8s, ' % self.pbtype result += '%s, ' % self.rules result += '%-8s, ' % self.allocation @@ -442,7 +467,7 @@ class ExtensionRange(Field): def tags(self): return '' - + def encoded_size(self, allmsgs): # We exclude extensions from the count, because they cannot be known # until runtime. Other option would be to return None here, but this @@ -521,7 +546,7 @@ class Message: def get_dependencies(self): '''Get list of type names that this structure refers to.''' - return [str(field.ctype) for field in self.fields] + return [str(field.ctype) for field in self.fields if field.allocation == 'STATIC'] def __str__(self): result = 'typedef struct _%s {\n' % self.name @@ -553,6 +578,34 @@ class Message: result += types + '\n' return result + def get_initializer(self, null_init): + if not self.ordered_fields: + return '{0}' + + parts = [] + for field in self.ordered_fields: + if field.allocation == 'STATIC': + if field.rules == 'REPEATED': + parts.append('0') + parts.append('{' + + ', '.join([field.get_initializer(null_init)] * field.max_count) + + '}') + elif field.rules == 'OPTIONAL': + parts.append('false') + parts.append(field.get_initializer(null_init)) + else: + parts.append(field.get_initializer(null_init)) + elif field.allocation == 'POINTER': + if field.rules == 'REPEATED': + parts.append('0') + parts.append('NULL') + elif field.allocation == 'CALLBACK': + if field.pbtype == 'EXTENSION': + parts.append('NULL') + else: + parts.append('{{NULL}, NULL}') + return '{' + ', '.join(parts) + '}' + def default_decl(self, declaration_only = False): result = "" for field in self.fields: @@ -639,6 +692,10 @@ def parse_file(fdesc, file_options): for names, message in iterate_messages(fdesc, base_name): message_options = get_nanopb_suboptions(message, file_options, names) + + if message_options.skip_message: + continue + messages.append(Message(names, message, message_options)) for enum in message.enum_type: enum_options = get_nanopb_suboptions(enum, message_options, names + enum.name) @@ -713,8 +770,8 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) symbol = make_identifier(headername) - yield '#ifndef _PB_%s_\n' % symbol - yield '#define _PB_%s_\n' % symbol + yield '#ifndef PB_%s_INCLUDED\n' % symbol + yield '#define PB_%s_INCLUDED\n' % symbol try: yield options.libformat % ('pb.h') except TypeError: @@ -724,9 +781,14 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio for dependency in dependencies: noext = os.path.splitext(dependency)[0] - yield options.genformat % (noext + '.' + options.extension + '.h') + yield options.genformat % (noext + options.extension + '.h') yield '\n' + yield '#if PB_PROTO_HEADER_VERSION != 30\n' + yield '#error Regenerate this file with the current version of nanopb generator.\n' + yield '#endif\n' + yield '\n' + yield '#ifdef __cplusplus\n' yield 'extern "C" {\n' yield '#endif\n\n' @@ -751,6 +813,15 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio yield msg.default_decl(True) yield '\n' + yield '/* Initializer values for message structs */\n' + for msg in messages: + identifier = '%s_init_default' % msg.name + yield '#define %-40s %s\n' % (identifier, msg.get_initializer(False)) + for msg in messages: + identifier = '%s_init_zero' % msg.name + yield '#define %-40s %s\n' % (identifier, msg.get_initializer(True)) + yield '\n' + yield '/* Field tags (for use in manual encoding/decoding) */\n' for msg in sort_dependencies(messages): for field in msg.fields: @@ -790,6 +861,11 @@ def generate_source(headername, enums, messages, extensions, options): yield options.genformat % (headername) yield '\n' + yield '#if PB_PROTO_HEADER_VERSION != 30\n' + yield '#error Regenerate this file with the current version of nanopb generator.\n' + yield '#endif\n' + yield '\n' + for msg in messages: yield msg.default_decl(False) @@ -844,7 +920,7 @@ def generate_source(headername, enums, messages, extensions, options): yield ' * numbers or field sizes that are larger than what can fit in 8 or 16 bit\n' yield ' * field descriptors.\n' yield ' */\n' - yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) + yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) yield '#endif\n\n' if worst < 65536: @@ -861,7 +937,7 @@ def generate_source(headername, enums, messages, extensions, options): yield ' * numbers or field sizes that are larger than what can fit in the default\n' yield ' * 8 bit descriptors.\n' yield ' */\n' - yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) + yield 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) yield '#endif\n\n' # Add check for sizeof(double) @@ -877,7 +953,7 @@ def generate_source(headername, enums, messages, extensions, options): yield ' * These are not directly supported by nanopb, but see example_avr_double.\n' yield ' * To get rid of this error, remove any double fields from your .proto.\n' yield ' */\n' - yield 'STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n' + yield 'PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n' yield '\n' @@ -959,8 +1035,8 @@ optparser = OptionParser( "Output will be written to file.pb.h and file.pb.c.") optparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[], help="Exclude file from generated #include list.") -optparser.add_option("-e", "--extension", dest="extension", metavar="EXTENSION", default="pb", - help="Set extension to use instead of 'pb' for generated files. [default: %default]") +optparser.add_option("-e", "--extension", dest="extension", metavar="EXTENSION", default=".pb", + help="Set extension to use instead of '.pb' for generated files. [default: %default]") optparser.add_option("-f", "--options-file", dest="options_file", metavar="FILE", default="%s.options", help="Set name of a separate generator options file.") optparser.add_option("-Q", "--generated-include-format", dest="genformat", @@ -1027,11 +1103,11 @@ def process_file(filename, fdesc, options): # Parse the file file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) enums, messages, extensions = parse_file(fdesc, file_options) - + # Decide the file names noext = os.path.splitext(filename)[0] - headername = noext + '.' + options.extension + '.h' - sourcename = noext + '.' + options.extension + '.c' + headername = noext + options.extension + '.h' + sourcename = noext + options.extension + '.c' headerbasename = os.path.basename(headername) # List of .proto files that should not be included in the C header file