From 536b79a8c43b5411d92367b60fbcf225c39089a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alr=C3=B8e?= Date: Mon, 18 Feb 2019 20:48:29 +0100 Subject: [PATCH] GW and Node example forked and running --- .README.md.swp | Bin 0 -> 16384 bytes .gitignore | 2 + ESP-Now_Node-airquality/lib/readme.txt | 36 - ESP-Now_Node-airquality/src/espnow_common.h | 1 - LICENSE => common/LICENSE | 0 .../src => common/include}/espnow_common.h | 0 {ESP-Now_GW => common}/lib/README.md | 0 common/lib/nanopb/messages.pb | 12 + common/lib/nanopb/messages.pb.c | 26 + common/lib/nanopb/messages.pb.h | 65 + {ESP-Now_GW => common}/lib/readme.txt | 0 common/nanopb/README.md | 3 + common/nanopb/generator/nanopb/options.proto | 123 ++ common/nanopb/generator/nanopb_generator.py | 1791 +++++++++++++++++ common/nanopb/generator/proto/Makefile | 4 + common/nanopb/generator/proto/__init__.py | 0 common/nanopb/generator/proto/__init__.pyc | Bin 0 -> 173 bytes .../proto/google/protobuf/descriptor.proto | 872 ++++++++ common/nanopb/generator/proto/nanopb.proto | 124 ++ common/nanopb/generator/proto/nanopb_pb2.py | 351 ++++ common/nanopb/generator/proto/nanopb_pb2.pyc | Bin 0 -> 8955 bytes common/nanopb/generator/proto/plugin.proto | 148 ++ common/nanopb/generator/proto/plugin_pb2.py | 188 ++ common/nanopb/generator/proto/plugin_pb2.pyc | Bin 0 -> 5188 bytes common/nanopb/generator/protoc-gen-nanopb | 13 + common/nanopb/generator/protoc-gen-nanopb.bat | 12 + common/out/.gitignore | 2 + common/src/common/model/messages.proto | 13 + common/tools/build_pb.bash | 11 + {ESP-Now_GW => gateway}/.gitignore | 0 .../.vscode/extensions.json | 0 {ESP-Now_GW => gateway}/.vscode/settings.json | 0 {ESP-Now_GW => gateway}/README.md | 0 gateway/include | 1 + .../lib/Ethernet/library.properties | 0 .../lib/Ethernet/src/Dhcp.cpp | 0 .../lib/Ethernet/src/Dhcp.h | 0 .../lib/Ethernet/src/Dns.cpp | 0 .../lib/Ethernet/src/Dns.h | 0 .../lib/Ethernet/src/Ethernet.cpp | 0 .../lib/Ethernet/src/Ethernet.h | 0 .../lib/Ethernet/src/EthernetClient.cpp | 0 .../lib/Ethernet/src/EthernetClient.h | 0 .../lib/Ethernet/src/EthernetServer.cpp | 0 .../lib/Ethernet/src/EthernetServer.h | 0 .../lib/Ethernet/src/EthernetUdp.cpp | 0 .../lib/Ethernet/src/EthernetUdp.h | 0 .../lib/Ethernet/src/Twitter.cpp | 0 .../lib/Ethernet/src/Twitter.h | 0 .../lib/Ethernet/src/util.h | 0 .../lib/Ethernet/src/utility/socket.cpp | 0 .../lib/Ethernet/src/utility/socket.h | 0 .../lib/Ethernet/src/utility/util.h | 0 .../lib/Ethernet/src/utility/w5100.cpp | 0 .../lib/Ethernet/src/utility/w5100.h | 0 .../lib/Ethernet/src/utility/w5200.cpp | 0 .../lib/Ethernet/src/utility/w5200.h | 0 .../lib/Ethernet/src/utility/w5500.cpp | 0 .../lib/Ethernet/src/utility/w5500.h | 0 gateway/lib/nanopb | 1 + {ESP-Now_GW => gateway}/platformio.ini | 7 +- {ESP-Now_GW => gateway}/src/espnow_gw.h | 0 {ESP-Now_GW => gateway}/src/espnow_gw.ino | 0 .../.gitignore | 0 .../.vscode/extensions.json | 0 .../.vscode/settings.json | 0 {ESP-Now_Node-airquality => sensor}/README.md | 0 sensor/include | 1 + sensor/lib | 1 + .../platformio.ini | 19 +- .../src/espnow_demo_controller.ino | 0 71 files changed, 3786 insertions(+), 41 deletions(-) create mode 100644 .README.md.swp delete mode 100644 ESP-Now_Node-airquality/lib/readme.txt delete mode 120000 ESP-Now_Node-airquality/src/espnow_common.h rename LICENSE => common/LICENSE (100%) rename {ESP-Now_GW/src => common/include}/espnow_common.h (100%) rename {ESP-Now_GW => common}/lib/README.md (100%) create mode 100644 common/lib/nanopb/messages.pb create mode 100644 common/lib/nanopb/messages.pb.c create mode 100644 common/lib/nanopb/messages.pb.h rename {ESP-Now_GW => common}/lib/readme.txt (100%) create mode 100644 common/nanopb/README.md create mode 100644 common/nanopb/generator/nanopb/options.proto create mode 100755 common/nanopb/generator/nanopb_generator.py create mode 100644 common/nanopb/generator/proto/Makefile create mode 100644 common/nanopb/generator/proto/__init__.py create mode 100644 common/nanopb/generator/proto/__init__.pyc create mode 100644 common/nanopb/generator/proto/google/protobuf/descriptor.proto create mode 100644 common/nanopb/generator/proto/nanopb.proto create mode 100644 common/nanopb/generator/proto/nanopb_pb2.py create mode 100644 common/nanopb/generator/proto/nanopb_pb2.pyc create mode 100644 common/nanopb/generator/proto/plugin.proto create mode 100644 common/nanopb/generator/proto/plugin_pb2.py create mode 100644 common/nanopb/generator/proto/plugin_pb2.pyc create mode 100755 common/nanopb/generator/protoc-gen-nanopb create mode 100644 common/nanopb/generator/protoc-gen-nanopb.bat create mode 100644 common/out/.gitignore create mode 100644 common/src/common/model/messages.proto create mode 100755 common/tools/build_pb.bash rename {ESP-Now_GW => gateway}/.gitignore (100%) rename {ESP-Now_GW => gateway}/.vscode/extensions.json (100%) rename {ESP-Now_GW => gateway}/.vscode/settings.json (100%) rename {ESP-Now_GW => gateway}/README.md (100%) create mode 120000 gateway/include rename {ESP-Now_GW => gateway}/lib/Ethernet/library.properties (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Dhcp.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Dhcp.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Dns.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Dns.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Ethernet.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Ethernet.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetClient.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetClient.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetServer.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetServer.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetUdp.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/EthernetUdp.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Twitter.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/Twitter.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/util.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/socket.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/socket.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/util.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5100.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5100.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5200.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5200.h (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5500.cpp (100%) rename {ESP-Now_GW => gateway}/lib/Ethernet/src/utility/w5500.h (100%) create mode 120000 gateway/lib/nanopb rename {ESP-Now_GW => gateway}/platformio.ini (83%) rename {ESP-Now_GW => gateway}/src/espnow_gw.h (100%) rename {ESP-Now_GW => gateway}/src/espnow_gw.ino (100%) rename {ESP-Now_Node-airquality => sensor}/.gitignore (100%) rename {ESP-Now_Node-airquality => sensor}/.vscode/extensions.json (100%) rename {ESP-Now_Node-airquality => sensor}/.vscode/settings.json (100%) rename {ESP-Now_Node-airquality => sensor}/README.md (100%) create mode 120000 sensor/include create mode 120000 sensor/lib rename {ESP-Now_Node-airquality => sensor}/platformio.ini (73%) rename {ESP-Now_Node-airquality => sensor}/src/espnow_demo_controller.ino (100%) diff --git a/.README.md.swp b/.README.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..ec6e514b14594c5abf7311741ccd63c8c5707f22 GIT binary patch literal 16384 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 THIS FILE -|- platformio.ini -|--src - |- main.c - -Then in `src/main.c` you should use: - -#include -#include - -// rest H/C/CPP code - -PlatformIO will find your libraries automatically, configure preprocessor's -include paths and build them. - -More information about PlatformIO Library Dependency Finder -- http://docs.platformio.org/page/librarymanager/ldf.html diff --git a/ESP-Now_Node-airquality/src/espnow_common.h b/ESP-Now_Node-airquality/src/espnow_common.h deleted file mode 120000 index 3c02ceb..0000000 --- a/ESP-Now_Node-airquality/src/espnow_common.h +++ /dev/null @@ -1 +0,0 @@ -../../ESP-Now_GW/src/espnow_common.h \ No newline at end of file diff --git a/LICENSE b/common/LICENSE similarity index 100% rename from LICENSE rename to common/LICENSE diff --git a/ESP-Now_GW/src/espnow_common.h b/common/include/espnow_common.h similarity index 100% rename from ESP-Now_GW/src/espnow_common.h rename to common/include/espnow_common.h diff --git a/ESP-Now_GW/lib/README.md b/common/lib/README.md similarity index 100% rename from ESP-Now_GW/lib/README.md rename to common/lib/README.md diff --git a/common/lib/nanopb/messages.pb b/common/lib/nanopb/messages.pb new file mode 100644 index 0000000..4f9d8b7 --- /dev/null +++ b/common/lib/nanopb/messages.pb @@ -0,0 +1,12 @@ + +¾ +messages.prototobalr"S +Report + +deviceName ( R +deviceName) +reading ( 2.tobalr.ReadingRreading"3 +Reading +name ( Rname +value (RvalueB +dk.tobalr.espsensornodes \ No newline at end of file diff --git a/common/lib/nanopb/messages.pb.c b/common/lib/nanopb/messages.pb.c new file mode 100644 index 0000000..c22309c --- /dev/null +++ b/common/lib/nanopb/messages.pb.c @@ -0,0 +1,26 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.2 at Mon Feb 18 20:16:25 2019. */ + +#include "messages.pb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t tobalr_Report_fields[3] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, tobalr_Report, deviceName, deviceName, 0), + PB_FIELD( 2, MESSAGE , REPEATED, CALLBACK, OTHER, tobalr_Report, reading, deviceName, &tobalr_Reading_fields), + PB_LAST_FIELD +}; + +const pb_field_t tobalr_Reading_fields[3] = { + PB_FIELD( 3, STRING , REQUIRED, CALLBACK, FIRST, tobalr_Reading, name, name, 0), + PB_FIELD( 4, FLOAT , REQUIRED, STATIC , OTHER, tobalr_Reading, value, name, 0), + PB_LAST_FIELD +}; + + +/* @@protoc_insertion_point(eof) */ diff --git a/common/lib/nanopb/messages.pb.h b/common/lib/nanopb/messages.pb.h new file mode 100644 index 0000000..fb3198d --- /dev/null +++ b/common/lib/nanopb/messages.pb.h @@ -0,0 +1,65 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.2 at Mon Feb 18 20:16:25 2019. */ + +#ifndef PB_TOBALR_MESSAGES_PB_H_INCLUDED +#define PB_TOBALR_MESSAGES_PB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct definitions */ +typedef struct _tobalr_Report { + pb_callback_t deviceName; + pb_callback_t reading; +/* @@protoc_insertion_point(struct:tobalr_Report) */ +} tobalr_Report; + +typedef struct _tobalr_Reading { + pb_callback_t name; + float value; +/* @@protoc_insertion_point(struct:tobalr_Reading) */ +} tobalr_Reading; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define tobalr_Report_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define tobalr_Reading_init_default {{{NULL}, NULL}, 0} +#define tobalr_Report_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define tobalr_Reading_init_zero {{{NULL}, NULL}, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define tobalr_Report_deviceName_tag 1 +#define tobalr_Report_reading_tag 2 +#define tobalr_Reading_name_tag 3 +#define tobalr_Reading_value_tag 4 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t tobalr_Report_fields[3]; +extern const pb_field_t tobalr_Reading_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* tobalr_Report_size depends on runtime parameters */ +/* tobalr_Reading_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define MESSAGES_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/ESP-Now_GW/lib/readme.txt b/common/lib/readme.txt similarity index 100% rename from ESP-Now_GW/lib/readme.txt rename to common/lib/readme.txt diff --git a/common/nanopb/README.md b/common/nanopb/README.md new file mode 100644 index 0000000..a837587 --- /dev/null +++ b/common/nanopb/README.md @@ -0,0 +1,3 @@ +## Nanopb +This directory contains a compiled version of nanopb built for linux x86 +https://jpa.kapsi.fi/nanopb/download/ \ No newline at end of file diff --git a/common/nanopb/generator/nanopb/options.proto b/common/nanopb/generator/nanopb/options.proto new file mode 100644 index 0000000..b94dca2 --- /dev/null +++ b/common/nanopb/generator/nanopb/options.proto @@ -0,0 +1,123 @@ +// This is a transitional file, to provide parallel support between the old +// nanopb.proto and new options.proto files. Eventually nanopb.proto will +// be left only for legacy code, but for now the generator is still also +// using it. However, your new code can start using this file already now. +// See pull request #241 for details: +// https://github.com/nanopb/nanopb/pull/241 + +// Custom options for defining: +// - Maximum size of string/bytes +// - Maximum number of elements in array +// +// These are used by nanopb to generate statically allocable structures +// for memory-limited environments. + +syntax = "proto2"; +import "google/protobuf/descriptor.proto"; + +package nanopb; +option java_package = "fi.kapsi.koti.jpa.nanopb"; + +enum FieldType { + FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible. + FT_CALLBACK = 1; // Always generate a callback field. + FT_POINTER = 4; // Always generate a dynamically allocated field. + FT_STATIC = 2; // Generate a static field or raise an exception if not possible. + FT_IGNORE = 3; // Ignore the field completely. + FT_INLINE = 5; // Legacy option, use the separate 'fixed_length' option instead +} + +enum IntSize { + IS_DEFAULT = 0; // Default, 32/64bit based on type in .proto + IS_8 = 8; + IS_16 = 16; + IS_32 = 32; + IS_64 = 64; +} + +// This is the inner options message, which basically defines options for +// a field. When it is used in message or file scope, it applies to all +// fields. +message Options { + // Allocated size for 'bytes' and 'string' fields. + // For string fields, this should include the space for null terminator. + optional int32 max_size = 1; + + // Maximum length for 'string' fields. Setting this is equivalent + // to setting max_size to a value of length+1. + optional int32 max_length = 14; + + // Allocated number of entries in arrays ('repeated' fields) + optional int32 max_count = 2; + + // Size of integer fields. Can save some memory if you don't need + // full 32 bits for the value. + optional IntSize int_size = 7 [default = IS_DEFAULT]; + + // Force type of field (callback or static allocation) + optional FieldType type = 3 [default = FT_DEFAULT]; + + // Use long names for enums, i.e. EnumName_EnumValue. + optional bool long_names = 4 [default = true]; + + // Add 'packed' attribute to generated structs. + // Note: this cannot be used on CPUs that break on unaligned + // accesses to variables. + optional bool packed_struct = 5 [default = false]; + + // Add 'packed' attribute to generated enums. + optional bool packed_enum = 10 [default = false]; + + // Skip this message + optional bool skip_message = 6 [default = false]; + + // Generate oneof fields as normal optional fields instead of union. + optional bool no_unions = 8 [default = false]; + + // integer type tag for a message + optional uint32 msgid = 9; + + // decode oneof as anonymous union + optional bool anonymous_oneof = 11 [default = false]; + + // Proto3 singular field does not generate a "has_" flag + optional bool proto3 = 12 [default = false]; + + // Generate an enum->string mapping function (can take up lots of space). + optional bool enum_to_string = 13 [default = false]; + + // Generate bytes arrays with fixed length + optional bool fixed_length = 15 [default = false]; + + // Generate repeated field with fixed count + optional bool fixed_count = 16 [default = false]; +} + +// Extensions to protoc 'Descriptor' type in order to define options +// inside a .proto file. +// +// Protocol Buffers extension number registry +// -------------------------------- +// Project: Nanopb +// Contact: Petteri Aimonen +// Web site: http://kapsi.fi/~jpa/nanopb +// Extensions: 1010 (all types) +// -------------------------------- + +extend google.protobuf.FileOptions { + optional Options fileopt = 1010; +} + +extend google.protobuf.MessageOptions { + optional Options msgopt = 1010; +} + +extend google.protobuf.EnumOptions { + optional Options enumopt = 1010; +} + +extend google.protobuf.FieldOptions { + optional Options fieldopt = 1010; +} + + diff --git a/common/nanopb/generator/nanopb_generator.py b/common/nanopb/generator/nanopb_generator.py new file mode 100755 index 0000000..906a1ac --- /dev/null +++ b/common/nanopb/generator/nanopb_generator.py @@ -0,0 +1,1791 @@ +#!/usr/bin/env python + +from __future__ import unicode_literals + +'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' +nanopb_version = "nanopb-0.3.9.2" + +import sys +import re +import codecs +from functools import reduce + +try: + # Add some dummy imports to keep packaging tools happy. + import google, distutils.util # bbfreeze seems to need these + import pkg_resources # pyinstaller / protobuf 2.5 seem to need these +except: + # Don't care, we will error out later if it is actually important. + pass + +try: + import google.protobuf.text_format as text_format + import google.protobuf.descriptor_pb2 as descriptor +except: + sys.stderr.write(''' + ************************************************************* + *** Could not import the Google protobuf Python libraries *** + *** Try installing package 'python-protobuf' or similar. *** + ************************************************************* + ''' + '\n') + raise + +try: + import proto.nanopb_pb2 as nanopb_pb2 + import proto.plugin_pb2 as plugin_pb2 +except TypeError: + sys.stderr.write(''' + **************************************************************************** + *** Got TypeError when importing the protocol definitions for generator. *** + *** This usually means that the protoc in your path doesn't match the *** + *** Python protobuf library version. *** + *** *** + *** Please check the output of the following commands: *** + *** which protoc *** + *** protoc --version *** + *** python -c 'import google.protobuf; print(google.protobuf.__file__)' *** + *** If you are not able to find the python protobuf version using the *** + *** above command, use this command. *** + *** pip freeze | grep -i protobuf *** + **************************************************************************** + ''' + '\n') + raise +except: + sys.stderr.write(''' + ******************************************************************** + *** Failed to import the protocol definitions for generator. *** + *** You have to run 'make' in the nanopb/generator/proto folder. *** + ******************************************************************** + ''' + '\n') + raise + +# --------------------------------------------------------------------------- +# Generation of single fields +# --------------------------------------------------------------------------- + +import time +import os.path + +# Values are tuple (c type, pb type, encoded size, int_size_allowed) +FieldD = descriptor.FieldDescriptorProto +datatypes = { + FieldD.TYPE_BOOL: ('bool', 'BOOL', 1, False), + FieldD.TYPE_DOUBLE: ('double', 'DOUBLE', 8, False), + FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4, False), + FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8, False), + FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4, False), + FieldD.TYPE_INT32: ('int32_t', 'INT32', 10, True), + FieldD.TYPE_INT64: ('int64_t', 'INT64', 10, True), + FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4, False), + FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8, False), + FieldD.TYPE_SINT32: ('int32_t', 'SINT32', 5, True), + FieldD.TYPE_SINT64: ('int64_t', 'SINT64', 10, True), + FieldD.TYPE_UINT32: ('uint32_t', 'UINT32', 5, True), + FieldD.TYPE_UINT64: ('uint64_t', 'UINT64', 10, True) +} + +# Integer size overrides (from .proto settings) +intsizes = { + nanopb_pb2.IS_8: 'int8_t', + nanopb_pb2.IS_16: 'int16_t', + nanopb_pb2.IS_32: 'int32_t', + nanopb_pb2.IS_64: 'int64_t', +} + +# String types (for python 2 / python 3 compatibility) +try: + strtypes = (unicode, str) +except NameError: + strtypes = (str, ) + + +class Names: + '''Keeps a set of nested names and formats them to C identifier.''' + def __init__(self, parts = ()): + if isinstance(parts, Names): + parts = parts.parts + elif isinstance(parts, strtypes): + parts = (parts,) + self.parts = tuple(parts) + + def __str__(self): + return '_'.join(self.parts) + + def __add__(self, other): + if isinstance(other, strtypes): + return Names(self.parts + (other,)) + elif isinstance(other, Names): + return Names(self.parts + other.parts) + elif isinstance(other, tuple): + return Names(self.parts + other) + else: + raise ValueError("Name parts should be of type str") + + def __eq__(self, other): + return isinstance(other, Names) and self.parts == other.parts + +def names_from_type_name(type_name): + '''Parse Names() from FieldDescriptorProto type_name''' + if type_name[0] != '.': + raise NotImplementedError("Lookup of non-absolute type names is not supported") + return Names(type_name[1:].split('.')) + +def varint_max_size(max_value): + '''Returns the maximum number of bytes a varint can take when encoded.''' + if max_value < 0: + max_value = 2**64 - max_value + for i in range(1, 11): + if (max_value >> (i * 7)) == 0: + return i + raise ValueError("Value too large for varint: " + str(max_value)) + +assert varint_max_size(-1) == 10 +assert varint_max_size(0) == 1 +assert varint_max_size(127) == 1 +assert varint_max_size(128) == 2 + +class EncodedSize: + '''Class used to represent the encoded size of a field or a message. + Consists of a combination of symbolic sizes and integer sizes.''' + def __init__(self, value = 0, symbols = []): + if isinstance(value, EncodedSize): + self.value = value.value + self.symbols = value.symbols + elif isinstance(value, strtypes + (Names,)): + self.symbols = [str(value)] + self.value = 0 + else: + self.value = value + self.symbols = symbols + + def __add__(self, other): + if isinstance(other, int): + return EncodedSize(self.value + other, self.symbols) + elif isinstance(other, strtypes + (Names,)): + return EncodedSize(self.value, self.symbols + [str(other)]) + elif isinstance(other, EncodedSize): + return EncodedSize(self.value + other.value, self.symbols + other.symbols) + else: + raise ValueError("Cannot add size: " + repr(other)) + + def __mul__(self, other): + if isinstance(other, int): + return EncodedSize(self.value * other, [str(other) + '*' + s for s in self.symbols]) + else: + raise ValueError("Cannot multiply size: " + repr(other)) + + def __str__(self): + if not self.symbols: + return str(self.value) + else: + return '(' + str(self.value) + ' + ' + ' + '.join(self.symbols) + ')' + + def upperlimit(self): + if not self.symbols: + return self.value + else: + return 2**32 - 1 + +class Enum: + def __init__(self, names, desc, enum_options): + '''desc is EnumDescriptorProto''' + + self.options = enum_options + self.names = names + + # by definition, `names` include this enum's name + base_name = Names(names.parts[:-1]) + + if enum_options.long_names: + self.values = [(names + x.name, x.number) for x in desc.value] + else: + self.values = [(base_name + x.name, x.number) for x in desc.value] + + self.value_longnames = [self.names + x.name for x in desc.value] + self.packed = enum_options.packed_enum + + def has_negative(self): + for n, v in self.values: + if v < 0: + return True + return False + + def encoded_size(self): + return max([varint_max_size(v) for n,v in self.values]) + + def __str__(self): + result = 'typedef enum _%s {\n' % self.names + result += ',\n'.join([" %s = %d" % x for x in self.values]) + result += '\n}' + + if self.packed: + result += ' pb_packed' + + result += ' %s;' % self.names + + result += '\n#define _%s_MIN %s' % (self.names, self.values[0][0]) + result += '\n#define _%s_MAX %s' % (self.names, self.values[-1][0]) + result += '\n#define _%s_ARRAYSIZE ((%s)(%s+1))' % (self.names, self.names, self.values[-1][0]) + + if not self.options.long_names: + # Define the long names always so that enum value references + # from other files work properly. + 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: + def __init__(self, worst = 0, checks = [], field_name = 'undefined'): + if isinstance(worst, list): + self.worst = max(i for i in worst if i is not None) + else: + self.worst = worst + + self.worst_field = field_name + self.checks = list(checks) + + def extend(self, extend, field_name = None): + self.worst = max(self.worst, extend.worst) + + if self.worst == extend.worst: + self.worst_field = extend.worst_field + + self.checks.extend(extend.checks) + +class Field: + def __init__(self, struct_name, desc, field_options): + '''desc is FieldDescriptorProto''' + self.tag = desc.number + self.struct_name = struct_name + self.union_name = None + self.name = desc.name + self.default = None + self.max_size = None + self.max_count = None + self.array_decl = "" + self.enc_size = None + self.ctype = None + self.fixed_count = False + + 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 + + if desc.HasField('default_value'): + self.default = desc.default_value + + # Check field rules, i.e. required/optional/repeated. + can_be_static = True + 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 + self.fixed_count = field_options.fixed_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) + + # Check if the field can be implemented with static allocation + # i.e. whether the data size is known. + if desc.type == FieldD.TYPE_STRING and self.max_size is None: + can_be_static = False + + if desc.type == FieldD.TYPE_BYTES and self.max_size is None: + can_be_static = False + + # Decide how the field data will be allocated + if field_options.type == nanopb_pb2.FT_DEFAULT: + if can_be_static: + field_options.type = nanopb_pb2.FT_STATIC + else: + field_options.type = nanopb_pb2.FT_CALLBACK + + if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static: + raise Exception("Field '%s' is defined as static, but max_size or " + "max_count is not given." % self.name) + + if field_options.fixed_count and self.max_count is None: + raise Exception("Field '%s' is defined as fixed count, " + "but max_count is not given." % self.name) + + if field_options.type == nanopb_pb2.FT_STATIC: + self.allocation = 'STATIC' + elif field_options.type == nanopb_pb2.FT_POINTER: + self.allocation = 'POINTER' + elif field_options.type == nanopb_pb2.FT_CALLBACK: + self.allocation = 'CALLBACK' + else: + raise NotImplementedError(field_options.type) + + # Decide the C data type to use in the struct. + if desc.type in datatypes: + self.ctype, self.pbtype, self.enc_size, isa = datatypes[desc.type] + + # Override the field size if user wants to use smaller integers + if isa and field_options.int_size != nanopb_pb2.IS_DEFAULT: + self.ctype = intsizes[field_options.int_size] + if desc.type == FieldD.TYPE_UINT32 or desc.type == FieldD.TYPE_UINT64: + self.ctype = 'u' + self.ctype; + elif desc.type == FieldD.TYPE_ENUM: + self.pbtype = 'ENUM' + self.ctype = names_from_type_name(desc.type_name) + if self.default is not None: + self.default = self.ctype + self.default + self.enc_size = None # Needs to be filled in when enum values are known + elif desc.type == FieldD.TYPE_STRING: + self.pbtype = 'STRING' + self.ctype = 'char' + if self.allocation == 'STATIC': + self.ctype = 'char' + 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: + if field_options.fixed_length: + self.pbtype = 'FIXED_LENGTH_BYTES' + + if self.max_size is None: + raise Exception("Field '%s' is defined as fixed length, " + "but max_size is not given." % self.name) + + self.enc_size = varint_max_size(self.max_size) + self.max_size + 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) + self.enc_size = None # Needs to be filled in after the message type is available + else: + raise NotImplementedError(desc.type) + + def __lt__(self, other): + return self.tag < other.tag + + def __str__(self): + result = '' + if self.allocation == 'POINTER': + if self.rules == 'REPEATED': + result += ' pb_size_t ' + self.name + '_count;\n' + + 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) + else: + result += ' %s *%s;' % (self.ctype, self.name) + elif self.allocation == 'CALLBACK': + result += ' pb_callback_t %s;' % self.name + else: + if self.rules == 'OPTIONAL' and self.allocation == 'STATIC': + result += ' bool has_' + self.name + ';\n' + elif (self.rules == 'REPEATED' and + self.allocation == 'STATIC' and + not self.fixed_count): + 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 PB_BYTES_ARRAY_T(%d) %s;\n' % (self.max_size, self.ctype) + else: + result = '' + return result + + def get_dependencies(self): + '''Get list of type names used by this field.''' + if self.allocation == 'STATIC': + return [str(self.ctype)] + else: + return [] + + def get_initializer(self, null_init, inner_init_only = False): + '''Return literal expression for this field's default value. + null_init: If True, initialize to a 0 value instead of default from .proto + inner_init_only: If True, exclude initialization for any count/has fields + ''' + + inner_init = None + if self.pbtype == 'MESSAGE': + if null_init: + inner_init = '%s_init_zero' % self.ctype + else: + inner_init = '%s_init_default' % self.ctype + elif self.default is None or null_init: + if self.pbtype == 'STRING': + 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_MIN' % self.ctype + else: + inner_init = '0' + else: + if self.pbtype == 'STRING': + data = codecs.escape_encode(self.default.encode('utf-8'))[0] + inner_init = '"' + data.decode('ascii') + '"' + elif self.pbtype == 'BYTES': + data = codecs.escape_decode(self.default)[0] + data = ["0x%02x" % c for c in bytearray(data)] + if len(data) == 0: + inner_init = '{0, {0}}' + else: + inner_init = '{%d, {%s}}' % (len(data), ','.join(data)) + elif self.pbtype == 'FIXED_LENGTH_BYTES': + data = codecs.escape_decode(self.default)[0] + data = ["0x%02x" % c for c in bytearray(data)] + 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']: + inner_init = str(self.default) + 'ull' + elif self.pbtype in ['SFIXED64', 'INT64']: + inner_init = str(self.default) + 'll' + else: + inner_init = str(self.default) + + if inner_init_only: + return inner_init + + outer_init = None + if self.allocation == 'STATIC': + if self.rules == 'REPEATED': + outer_init = '' + if not self.fixed_count: + outer_init += '0, ' + outer_init += '{' + outer_init += ', '.join([inner_init] * self.max_count) + outer_init += '}' + elif self.rules == 'OPTIONAL': + outer_init = 'false, ' + inner_init + else: + outer_init = inner_init + elif self.allocation == 'POINTER': + if self.rules == 'REPEATED': + outer_init = '0, NULL' + else: + outer_init = 'NULL' + elif self.allocation == 'CALLBACK': + if self.pbtype == 'EXTENSION': + outer_init = 'NULL' + else: + outer_init = '{{NULL}, NULL}' + + return outer_init + + def default_decl(self, declaration_only = False): + '''Return definition for this field's default value.''' + if self.default is None: + return None + + ctype = self.ctype + default = self.get_initializer(False, True) + array_decl = '' + + if self.pbtype == 'STRING': + if self.allocation != 'STATIC': + return None # Not implemented + array_decl = '[%d]' % self.max_size + 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) + else: + return 'const %s %s_default%s = %s;' % (ctype, self.struct_name + self.name, array_decl, default) + + def tags(self): + '''Return the #define for the tag number of this 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, 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. For OneOf + unions, union_index is the index of this field inside the OneOf. + ''' + + if self.rules == 'ONEOF': + if self.anonymous: + result = ' PB_ANONYMOUS_ONEOF_FIELD(%s, ' % self.union_name + else: + result = ' PB_ONEOF_FIELD(%s, ' % self.union_name + elif self.fixed_count: + result = ' PB_REPEATED_FIXED_COUNT(' + else: + result = ' PB_FIELD(' + + result += '%3d, ' % self.tag + result += '%-8s, ' % self.pbtype + if not self.fixed_count: + result += '%s, ' % self.rules + result += '%-8s, ' % self.allocation + + 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) + + if self.pbtype == 'MESSAGE': + result += '&%s_fields)' % self.submsgname + elif self.default is None: + result += '0)' + 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 + else: + result += '&%s_default)' % (self.struct_name + self.name) + + return result + + def get_last_field_name(self): + return self.name + + def largest_field_value(self): + '''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' 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: + check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name)) + else: + 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, + ('%s.%s' % (self.struct_name, self.name))) + + def encoded_size(self, dependencies): + '''Return the maximum size that this field can take when encoded, + including the field tag. If the size cannot be determined, returns + None.''' + + if self.allocation != 'STATIC': + return None + + if self.pbtype == 'MESSAGE': + encsize = None + if str(self.submsgname) in dependencies: + submsg = dependencies[str(self.submsgname)] + encsize = submsg.encoded_size(dependencies) + if encsize is not None: + # Include submessage length prefix + encsize += varint_max_size(encsize.upperlimit()) + else: + my_msg = dependencies.get(str(self.struct_name)) + if my_msg and submsg.protofile == my_msg.protofile: + # The dependency is from the same file and size cannot be + # determined for it, thus we know it will not be possible + # in runtime either. + return None + + if encsize is None: + # Submessage or its size cannot be found. + # This can occur if submessage is defined in different + # file, and it or its .options could not be found. + # Instead of direct numeric value, reference the size that + # has been #defined in the other file. + encsize = EncodedSize(self.submsgname + 'size') + + # We will have to make a conservative assumption on the length + # prefix size, though. + encsize += 5 + + elif self.pbtype in ['ENUM', 'UENUM']: + if str(self.ctype) in dependencies: + enumtype = dependencies[str(self.ctype)] + encsize = enumtype.encoded_size() + else: + # Conservative assumption + encsize = 10 + + elif self.enc_size is None: + raise RuntimeError("Could not determine encoded size for %s.%s" + % (self.struct_name, self.name)) + else: + encsize = EncodedSize(self.enc_size) + + encsize += varint_max_size(self.tag << 3) # Tag + wire type + + if self.rules == 'REPEATED': + # Decoders must be always able to handle unpacked arrays. + # Therefore we have to reserve space for it, even though + # we emit packed arrays ourselves. For length of 1, packed + # arrays are larger however so we need to add allowance + # for the length byte. + encsize *= self.max_count + + if self.max_count == 1: + encsize += 1 + + return encsize + + +class ExtensionRange(Field): + def __init__(self, struct_name, range_start, field_options): + '''Implements a special pb_extension_t* field in an extensible message + structure. The range_start signifies the index at which the extensions + start. Not necessarily all tags above this are extensions, it is merely + a speed optimization. + ''' + self.tag = range_start + self.struct_name = struct_name + self.name = 'extensions' + self.pbtype = 'EXTENSION' + self.rules = 'OPTIONAL' + self.allocation = 'CALLBACK' + self.ctype = 'pb_extension_t' + self.array_decl = '' + self.default = None + self.max_size = 0 + self.max_count = 0 + self.fixed_count = False + + def __str__(self): + return ' pb_extension_t *extensions;' + + def types(self): + return '' + + def tags(self): + return '' + + def encoded_size(self, dependencies): + # We exclude extensions from the count, because they cannot be known + # until runtime. Other option would be to return None here, but this + # way the value remains useful if extensions are not used. + return EncodedSize(0) + +class ExtensionField(Field): + def __init__(self, fullname, desc, field_options): + self.fullname = fullname + self.extendee_name = names_from_type_name(desc.extendee) + Field.__init__(self, self.fullname + 'struct', desc, field_options) + + if self.rules != 'OPTIONAL': + self.skip = True + else: + self.skip = False + self.rules = 'OPTEXT' + + def tags(self): + '''Return the #define for the tag number of this field.''' + identifier = '%s_tag' % self.fullname + return '#define %-40s %d\n' % (identifier, self.tag) + + def extension_decl(self): + '''Declaration of the extension type in the .pb.h file''' + if self.skip: + msg = '/* Extension field %s was skipped because only "optional"\n' % self.fullname + msg +=' type of extension fields is currently supported. */\n' + return msg + + return ('extern const pb_extension_type_t %s; /* field type: %s */\n' % + (self.fullname, str(self).strip())) + + def extension_def(self): + '''Definition of the extension type in the .pb.c file''' + + if self.skip: + return '' + + result = 'typedef struct {\n' + result += str(self) + result += '\n} %s;\n\n' % self.struct_name + result += ('static const pb_field_t %s_field = \n %s;\n\n' % + (self.fullname, self.pb_field_t(None))) + result += 'const pb_extension_type_t %s = {\n' % self.fullname + result += ' NULL,\n' + result += ' NULL,\n' + result += ' &%s_field\n' % self.fullname + result += '};\n' + return result + + +# --------------------------------------------------------------------------- +# Generation of oneofs (unions) +# --------------------------------------------------------------------------- + +class OneOf(Field): + def __init__(self, struct_name, oneof_desc): + self.struct_name = struct_name + self.name = oneof_desc.name + self.ctype = 'union' + self.pbtype = 'oneof' + self.fields = [] + self.allocation = 'ONEOF' + self.default = None + self.rules = 'ONEOF' + self.anonymous = False + + def add_field(self, field): + if field.allocation == 'CALLBACK': + raise Exception("Callback fields inside of oneof are not supported" + + " (field %s)" % field.name) + + field.union_name = self.name + field.rules = 'ONEOF' + field.anonymous = self.anonymous + self.fields.append(field) + self.fields.sort(key = lambda f: f.tag) + + # Sort by the lowest tag number inside union + self.tag = min([f.tag for f in self.fields]) + + def __str__(self): + result = '' + if self.fields: + result += ' pb_size_t which_' + self.name + ";\n" + result += ' union {\n' + for f in self.fields: + result += ' ' + str(f).replace('\n', '\n ') + '\n' + if self.anonymous: + result += ' };' + else: + result += ' } ' + self.name + ';' + return result + + def types(self): + return ''.join([f.types() for f in self.fields]) + + def get_dependencies(self): + deps = [] + for f in self.fields: + deps += f.get_dependencies() + return deps + + def get_initializer(self, null_init): + return '0, {' + self.fields[0].get_initializer(null_init) + '}' + + def default_decl(self, declaration_only = False): + return None + + def tags(self): + return ''.join([f.tags() for f in self.fields]) + + def pb_field_t(self, prev_field_name): + 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: + return self.fields[-1].name + else: + return self.name + '.' + self.fields[-1].name + + def largest_field_value(self): + largest = FieldMaxSize() + for f in self.fields: + largest.extend(f.largest_field_value()) + return largest + + def encoded_size(self, dependencies): + '''Returns the size of the largest oneof field.''' + largest = 0 + symbols = [] + for f in self.fields: + size = EncodedSize(f.encoded_size(dependencies)) + if size is None or size.value is None: + return None + elif size.symbols: + symbols.append((f.tag, size.symbols[0])) + elif size.value > largest: + largest = size.value + + if not symbols: + # Simple case, all sizes were known at generator time + return largest + + if largest > 0: + # Some sizes were known, some were not + symbols.insert(0, (0, largest)) + + if len(symbols) == 1: + # Only one symbol was needed + return EncodedSize(5, [symbols[0][1]]) + else: + # Use sizeof(union{}) construct to find the maximum size of + # submessages. + union_def = ' '.join('char f%d[%s];' % s for s in symbols) + return EncodedSize(5, ['sizeof(union{%s})' % union_def]) + +# --------------------------------------------------------------------------- +# Generation of messages (structures) +# --------------------------------------------------------------------------- + + +class Message: + def __init__(self, names, desc, message_options): + self.name = names + self.fields = [] + self.oneofs = {} + no_unions = [] + + if message_options.msgid: + self.msgid = message_options.msgid + + if hasattr(desc, 'oneof_decl'): + for i, f in enumerate(desc.oneof_decl): + oneof_options = get_nanopb_suboptions(desc, message_options, self.name + f.name) + if oneof_options.no_unions: + no_unions.append(i) # No union, but add fields normally + elif oneof_options.type == nanopb_pb2.FT_IGNORE: + pass # No union and skip fields also + else: + oneof = OneOf(self.name, f) + if oneof_options.anonymous_oneof: + oneof.anonymous = True + self.oneofs[i] = oneof + self.fields.append(oneof) + else: + sys.stderr.write('Note: This Python protobuf library has no OneOf support\n') + + for f in desc.field: + field_options = get_nanopb_suboptions(f, message_options, self.name + f.name) + if field_options.type == nanopb_pb2.FT_IGNORE: + continue + + field = Field(self.name, f, field_options) + if (hasattr(f, 'oneof_index') and + f.HasField('oneof_index') and + f.oneof_index not in no_unions): + if f.oneof_index in self.oneofs: + self.oneofs[f.oneof_index].add_field(field) + else: + self.fields.append(field) + + if len(desc.extension_range) > 0: + field_options = get_nanopb_suboptions(desc, message_options, self.name + 'extensions') + range_start = min([r.start for r in desc.extension_range]) + if field_options.type != nanopb_pb2.FT_IGNORE: + self.fields.append(ExtensionRange(self.name, range_start, field_options)) + + self.packed = message_options.packed_struct + self.ordered_fields = self.fields[:] + self.ordered_fields.sort() + + def get_dependencies(self): + '''Get list of type names that this structure refers to.''' + deps = [] + for f in self.fields: + deps += f.get_dependencies() + return deps + + def __str__(self): + result = 'typedef struct _%s {\n' % self.name + + if not self.ordered_fields: + # Empty structs are not allowed in C standard. + # Therefore add a dummy field if an empty message occurs. + result += ' char dummy_field;' + + result += '\n'.join([str(f) for f in self.ordered_fields]) + result += '\n/* @@protoc_insertion_point(struct:%s) */' % self.name + result += '\n}' + + if self.packed: + result += ' pb_packed' + + result += ' %s;' % self.name + + if self.packed: + result = 'PB_PACKED_STRUCT_START\n' + result + result += '\nPB_PACKED_STRUCT_END' + + return result + + def types(self): + return ''.join([f.types() for f in self.fields]) + + def get_initializer(self, null_init): + if not self.ordered_fields: + return '{0}' + + parts = [] + for field in self.ordered_fields: + parts.append(field.get_initializer(null_init)) + return '{' + ', '.join(parts) + '}' + + def default_decl(self, declaration_only = False): + result = "" + for field in self.fields: + default = field.default_decl(declaration_only) + if default is not None: + result += default + '\n' + return result + + def count_required_fields(self): + '''Returns number of required fields inside this message''' + count = 0 + for f in self.fields: + if not isinstance(f, OneOf): + if f.rules == 'REQUIRED': + count += 1 + return count + + def count_all_fields(self): + count = 0 + for f in self.fields: + if isinstance(f, OneOf): + count += len(f.fields) + else: + count += 1 + return count + + def fields_declaration(self): + result = 'extern const pb_field_t %s_fields[%d];' % (self.name, self.count_all_fields() + 1) + return result + + def fields_definition(self): + result = 'const pb_field_t %s_fields[%d] = {\n' % (self.name, self.count_all_fields() + 1) + + prev = None + for field in self.ordered_fields: + result += field.pb_field_t(prev) + result += ',\n' + prev = field.get_last_field_name() + + result += ' PB_LAST_FIELD\n};' + return result + + def encoded_size(self, dependencies): + '''Return the maximum size that this message can take when encoded. + If the size cannot be determined, returns None. + ''' + size = EncodedSize(0) + for field in self.fields: + fsize = field.encoded_size(dependencies) + if fsize is None: + return None + size += fsize + + return size + + +# --------------------------------------------------------------------------- +# Processing of entire .proto files +# --------------------------------------------------------------------------- + +def iterate_messages(desc, flatten = False, names = Names()): + '''Recursively find all messages. For each, yield name, DescriptorProto.''' + if hasattr(desc, 'message_type'): + submsgs = desc.message_type + else: + submsgs = desc.nested_type + + for submsg in submsgs: + sub_names = names + submsg.name + if flatten: + yield Names(submsg.name), submsg + else: + yield sub_names, submsg + + for x in iterate_messages(submsg, flatten, sub_names): + yield x + +def iterate_extensions(desc, flatten = False, names = Names()): + '''Recursively find all extensions. + For each, yield name, FieldDescriptorProto. + ''' + for extension in desc.extension: + yield names, extension + + for subname, subdesc in iterate_messages(desc, flatten, names): + for extension in subdesc.extension: + yield subname, extension + +def toposort2(data): + '''Topological sort. + From http://code.activestate.com/recipes/577413-topological-sort/ + This function is under the MIT license. + ''' + for k, v in list(data.items()): + v.discard(k) # Ignore self dependencies + extra_items_in_deps = reduce(set.union, list(data.values()), set()) - set(data.keys()) + data.update(dict([(item, set()) for item in extra_items_in_deps])) + while True: + ordered = set(item for item,dep in list(data.items()) if not dep) + if not ordered: + break + for item in sorted(ordered): + yield item + data = dict([(item, (dep - ordered)) for item,dep in list(data.items()) + if item not in ordered]) + assert not data, "A cyclic dependency exists amongst %r" % data + +def sort_dependencies(messages): + '''Sort a list of Messages based on dependencies.''' + dependencies = {} + message_by_name = {} + for message in messages: + dependencies[str(message.name)] = set(message.get_dependencies()) + message_by_name[str(message.name)] = message + + for msgname in toposort2(dependencies): + if msgname in message_by_name: + yield message_by_name[msgname] + +def make_identifier(headername): + '''Make #ifndef identifier that contains uppercase A-Z and digits 0-9''' + result = "" + for c in headername.upper(): + if c.isalnum(): + result += c + else: + result += '_' + return result + +class ProtoFile: + def __init__(self, fdesc, file_options): + '''Takes a FileDescriptorProto and parses it.''' + self.fdesc = fdesc + self.file_options = file_options + self.dependencies = {} + self.parse() + + # Some of types used in this file probably come from the file itself. + # Thus it has implicit dependency on itself. + self.add_dependency(self) + + def parse(self): + self.enums = [] + self.messages = [] + self.extensions = [] + + mangle_names = self.file_options.mangle_names + flatten = mangle_names == nanopb_pb2.M_FLATTEN + strip_prefix = None + if mangle_names == nanopb_pb2.M_STRIP_PACKAGE: + strip_prefix = "." + self.fdesc.package + + def create_name(names): + if mangle_names == nanopb_pb2.M_NONE: + return base_name + names + elif mangle_names == nanopb_pb2.M_STRIP_PACKAGE: + return Names(names) + else: + single_name = names + if isinstance(names, Names): + single_name = names.parts[-1] + return Names(single_name) + + def mangle_field_typename(typename): + if mangle_names == nanopb_pb2.M_FLATTEN: + return "." + typename.split(".")[-1] + elif strip_prefix is not None and typename.startswith(strip_prefix): + return typename[len(strip_prefix):] + else: + return typename + + if self.fdesc.package: + base_name = Names(self.fdesc.package.split('.')) + else: + base_name = Names() + + for enum in self.fdesc.enum_type: + name = create_name(enum.name) + enum_options = get_nanopb_suboptions(enum, self.file_options, name) + self.enums.append(Enum(name, enum, enum_options)) + + for names, message in iterate_messages(self.fdesc, flatten): + name = create_name(names) + message_options = get_nanopb_suboptions(message, self.file_options, name) + + if message_options.skip_message: + continue + + for field in message.field: + if field.type in (FieldD.TYPE_MESSAGE, FieldD.TYPE_ENUM): + field.type_name = mangle_field_typename(field.type_name) + + + self.messages.append(Message(name, message, message_options)) + for enum in message.enum_type: + name = create_name(names + enum.name) + enum_options = get_nanopb_suboptions(enum, message_options, name) + self.enums.append(Enum(name, enum, enum_options)) + + for names, extension in iterate_extensions(self.fdesc, flatten): + name = create_name(names + extension.name) + field_options = get_nanopb_suboptions(extension, self.file_options, name) + if field_options.type != nanopb_pb2.FT_IGNORE: + self.extensions.append(ExtensionField(name, extension, field_options)) + + def add_dependency(self, other): + for enum in other.enums: + self.dependencies[str(enum.names)] = enum + enum.protofile = other + + for msg in other.messages: + self.dependencies[str(msg.name)] = msg + msg.protofile = other + + # Fix field default values where enum short names are used. + for enum in other.enums: + if not enum.options.long_names: + for message in self.messages: + for field in message.fields: + if field.default in enum.value_longnames: + idx = enum.value_longnames.index(field.default) + field.default = enum.values[idx][0] + + # Fix field data types where enums have negative values. + for enum in other.enums: + if not enum.has_negative(): + for message in self.messages: + for field in message.fields: + if field.pbtype == 'ENUM' and field.ctype == enum.names: + field.pbtype = 'UENUM' + + def generate_header(self, includes, headername, options): + '''Generate content for a header file. + Generates strings, which should be concatenated and stored to file. + ''' + + yield '/* Automatically generated nanopb header */\n' + if options.notimestamp: + yield '/* Generated by %s */\n\n' % (nanopb_version) + else: + yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) + + 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: + yield options.libformat % ('pb.h') + except TypeError: + # no %s specified - use whatever was passed in as options.libformat + yield options.libformat + yield '\n' + + for incfile in includes: + noext = os.path.splitext(incfile)[0] + yield options.genformat % (noext + options.extension + options.header_extension) + yield '\n' + + yield '/* @@protoc_insertion_point(includes) */\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' + + if self.enums: + yield '/* Enum definitions */\n' + for enum in self.enums: + yield str(enum) + '\n\n' + + if self.messages: + yield '/* Struct definitions */\n' + for msg in sort_dependencies(self.messages): + yield msg.types() + yield str(msg) + '\n\n' + + if self.extensions: + yield '/* Extensions */\n' + for extension in self.extensions: + yield extension.extension_decl() + yield '\n' + + if self.messages: + yield '/* Default values for struct fields */\n' + for msg in self.messages: + yield msg.default_decl(True) + yield '\n' + + yield '/* Initializer values for message structs */\n' + for msg in self.messages: + identifier = '%s_init_default' % msg.name + yield '#define %-40s %s\n' % (identifier, msg.get_initializer(False)) + for msg in self.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(self.messages): + for field in msg.fields: + yield field.tags() + for extension in self.extensions: + yield extension.tags() + yield '\n' + + yield '/* Struct field encoding specification for nanopb */\n' + for msg in self.messages: + yield msg.fields_declaration() + '\n' + yield '\n' + + yield '/* Maximum encoded size of messages (where known) */\n' + for msg in self.messages: + msize = msg.encoded_size(self.dependencies) + identifier = '%s_size' % msg.name + if msize is not None: + yield '#define %-40s %s\n' % (identifier, msize) + else: + yield '/* %s depends on runtime parameters */\n' % identifier + yield '\n' + + yield '/* Message IDs (where set with "msgid" option) */\n' + + yield '#ifdef PB_MSGID\n' + for msg in self.messages: + if hasattr(msg,'msgid'): + yield '#define PB_MSG_%d %s\n' % (msg.msgid, msg.name) + yield '\n' + + symbol = make_identifier(headername.split('.')[0]) + yield '#define %s_MESSAGES \\\n' % symbol + + for msg in self.messages: + m = "-1" + msize = msg.encoded_size(self.dependencies) + if msize is not None: + m = msize + if hasattr(msg,'msgid'): + yield '\tPB_MSG(%d,%s,%s) \\\n' % (msg.msgid, m, msg.name) + yield '\n' + + for msg in self.messages: + if hasattr(msg,'msgid'): + yield '#define %s_msgid %d\n' % (msg.name, msg.msgid) + yield '\n' + + yield '#endif\n\n' + + yield '#ifdef __cplusplus\n' + yield '} /* extern "C" */\n' + yield '#endif\n' + + # End of header + yield '/* @@protoc_insertion_point(eof) */\n' + yield '\n#endif\n' + + def generate_source(self, headername, options): + '''Generate content for a source file.''' + + yield '/* Automatically generated nanopb constant definitions */\n' + if options.notimestamp: + yield '/* Generated by %s */\n\n' % (nanopb_version) + else: + yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) + yield options.genformat % (headername) + yield '\n' + yield '/* @@protoc_insertion_point(includes) */\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 self.messages: + yield msg.default_decl(False) + + yield '\n\n' + + for msg in self.messages: + yield msg.fields_definition() + '\n\n' + + 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()) + largest_count = largest_msg.count_required_fields() + if largest_count > 64: + yield '\n/* Check that missing required fields will be properly detected */\n' + yield '#if PB_MAX_REQUIRED_FIELDS < %d\n' % largest_count + yield '#error Properly detecting missing required fields in %s requires \\\n' % largest_msg.name + yield ' setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count + yield '#endif\n' + + max_field = FieldMaxSize() + checks_msgnames = [] + for msg in self.messages: + checks_msgnames.append(msg.name) + for field in msg.fields: + max_field.extend(field.largest_field_value()) + for field in self.extensions: + max_field.extend(field.largest_field_value()) + + worst = max_field.worst + worst_field = max_field.worst_field + checks = max_field.checks + + if worst > 255 or checks: + yield '\n/* Check that field information fits in pb_field_t */\n' + + if worst > 65535 or checks: + yield '#if !defined(PB_FIELD_32BIT)\n' + if worst > 65535: + yield '#error Field descriptor for %s is too large. Define PB_FIELD_32BIT to fix this.\n' % worst_field + else: + assertion = ' && '.join(str(c) + ' < 65536' for c in checks) + msgs = '_'.join(str(n) for n in checks_msgnames) + yield '/* If you get an error here, it means that you need to define PB_FIELD_32BIT\n' + yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n' + yield ' * \n' + yield ' * The reason you need to do this is that some of your messages contain tag\n' + 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 'PB_STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) + yield '#endif\n\n' + + if worst < 65536: + yield '#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)\n' + if worst > 255: + yield '#error Field descriptor for %s is too large. Define PB_FIELD_16BIT to fix this.\n' % worst_field + else: + assertion = ' && '.join(str(c) + ' < 256' for c in checks) + msgs = '_'.join(str(n) for n in checks_msgnames) + yield '/* If you get an error here, it means that you need to define PB_FIELD_16BIT\n' + yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n' + yield ' * \n' + yield ' * The reason you need to do this is that some of your messages contain tag\n' + yield ' * numbers or field sizes that are larger than what can fit in the default\n' + yield ' * 8 bit descriptors.\n' + yield ' */\n' + 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) + has_double = False + for msg in self.messages: + for field in msg.fields: + if field.ctype == 'double': + has_double = True + + if has_double: + yield '\n' + yield '/* On some platforms (such as AVR), double is really float.\n' + 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 'PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n' + + yield '\n' + yield '/* @@protoc_insertion_point(eof) */\n' + +# --------------------------------------------------------------------------- +# Options parsing for the .proto files +# --------------------------------------------------------------------------- + +from fnmatch import fnmatch + +def read_options_file(infile): + '''Parse a separate options file to list: + [(namemask, options), ...] + ''' + results = [] + data = infile.read() + data = re.sub('/\*.*?\*/', '', data, flags = re.MULTILINE) + data = re.sub('//.*?$', '', data, flags = re.MULTILINE) + data = re.sub('#.*?$', '', data, flags = re.MULTILINE) + for i, line in enumerate(data.split('\n')): + line = line.strip() + if not line: + continue + + parts = line.split(None, 1) + + if len(parts) < 2: + sys.stderr.write("%s:%d: " % (infile.name, i + 1) + + "Option lines should have space between field name and options. " + + "Skipping line: '%s'\n" % line) + continue + + opts = nanopb_pb2.NanoPBOptions() + + try: + text_format.Merge(parts[1], opts) + except Exception as e: + sys.stderr.write("%s:%d: " % (infile.name, i + 1) + + "Unparseable option line: '%s'. " % line + + "Error: %s\n" % str(e)) + continue + results.append((parts[0], opts)) + + return results + +class Globals: + '''Ugly global variables, should find a good way to pass these.''' + verbose_options = False + separate_options = [] + matched_namemasks = set() + +def get_nanopb_suboptions(subdesc, options, name): + '''Get copy of options, and merge information from subdesc.''' + 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: + if fnmatch(dotname, namemask): + Globals.matched_namemasks.add(namemask) + new_options.MergeFrom(options) + + # Handle options defined in .proto + if isinstance(subdesc.options, descriptor.FieldOptions): + ext_type = nanopb_pb2.nanopb + elif isinstance(subdesc.options, descriptor.FileOptions): + ext_type = nanopb_pb2.nanopb_fileopt + elif isinstance(subdesc.options, descriptor.MessageOptions): + ext_type = nanopb_pb2.nanopb_msgopt + elif isinstance(subdesc.options, descriptor.EnumOptions): + ext_type = nanopb_pb2.nanopb_enumopt + else: + raise Exception("Unknown options type") + + if subdesc.options.HasExtension(ext_type): + ext = subdesc.options.Extensions[ext_type] + new_options.MergeFrom(ext) + + if Globals.verbose_options: + sys.stderr.write("Options for " + dotname + ": ") + sys.stderr.write(text_format.MessageToString(new_options) + "\n") + + return new_options + + +# --------------------------------------------------------------------------- +# Command line interface +# --------------------------------------------------------------------------- + +import sys +import os.path +from optparse import OptionParser + +optparser = OptionParser( + usage = "Usage: nanopb_generator.py [options] file.pb ...", + epilog = "Compile file.pb from file.proto by: 'protoc -ofile.pb file.proto'. " + + "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("-H", "--header-extension", dest="header_extension", metavar="EXTENSION", default=".h", + help="Set extension to use for generated header files. [default: %default]") +optparser.add_option("-S", "--source-extension", dest="source_extension", metavar="EXTENSION", default=".c", + help="Set extension to use for generated source 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("-I", "--options-path", dest="options_path", metavar="DIR", + action="append", default = [], + help="Search for .options files additionally in this path") +optparser.add_option("-D", "--output-dir", dest="output_dir", + metavar="OUTPUTDIR", default=None, + help="Output directory of .pb.h and .pb.c files") +optparser.add_option("-Q", "--generated-include-format", dest="genformat", + metavar="FORMAT", default='#include "%s"\n', + help="Set format string to use for including other .pb.h files. [default: %default]") +optparser.add_option("-L", "--library-include-format", dest="libformat", + metavar="FORMAT", default='#include <%s>\n', + help="Set format string to use for including the nanopb pb.h header. [default: %default]") +optparser.add_option("--strip-path", dest="strip_path", action="store_true", default=True, + help="Strip directory path from #included .pb.h file name [default: %default]") +optparser.add_option("--no-strip-path", dest="strip_path", action="store_false", + help="Opposite of --strip-path") +optparser.add_option("-T", "--no-timestamp", dest="notimestamp", action="store_true", default=False, + help="Don't add timestamp to .pb.h and .pb.c preambles") +optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, + help="Don't print anything except errors.") +optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, + help="Print more information.") +optparser.add_option("-s", dest="settings", metavar="OPTION:VALUE", action="append", default=[], + help="Set generator option (max_size, max_count etc.).") + +def parse_file(filename, fdesc, options): + '''Parse a single file. Returns a ProtoFile instance.''' + toplevel_options = nanopb_pb2.NanoPBOptions() + for s in options.settings: + text_format.Merge(s, toplevel_options) + + if not fdesc: + data = open(filename, 'rb').read() + fdesc = descriptor.FileDescriptorSet.FromString(data).file[0] + + # Check if there is a separate .options file + had_abspath = False + try: + optfilename = options.options_file % os.path.splitext(filename)[0] + except TypeError: + # No %s specified, use the filename as-is + optfilename = options.options_file + had_abspath = True + + paths = ['.'] + options.options_path + for p in paths: + if os.path.isfile(os.path.join(p, optfilename)): + optfilename = os.path.join(p, optfilename) + if options.verbose: + sys.stderr.write('Reading options from ' + optfilename + '\n') + Globals.separate_options = read_options_file(open(optfilename, "rU")) + break + else: + # If we are given a full filename and it does not exist, give an error. + # However, don't give error when we automatically look for .options file + # with the same name as .proto. + if options.verbose or had_abspath: + sys.stderr.write('Options file not found: ' + optfilename + '\n') + Globals.separate_options = [] + + Globals.matched_namemasks = set() + + # Parse the file + file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) + f = ProtoFile(fdesc, file_options) + f.optfilename = optfilename + + return f + +def process_file(filename, fdesc, options, other_files = {}): + '''Process a single file. + filename: The full path to the .proto or .pb source file, as string. + fdesc: The loaded FileDescriptorSet, or None to read from the input file. + options: Command line options as they come from OptionsParser. + + Returns a dict: + {'headername': Name of header file, + 'headerdata': Data for the .h header file, + 'sourcename': Name of the source code file, + 'sourcedata': Data for the .c source code file + } + ''' + f = parse_file(filename, fdesc, options) + + # Provide dependencies if available + for dep in f.fdesc.dependency: + if dep in other_files: + f.add_dependency(other_files[dep]) + + # Decide the file names + noext = os.path.splitext(filename)[0] + headername = noext + options.extension + options.header_extension + sourcename = noext + options.extension + options.source_extension + + if options.strip_path: + headerbasename = os.path.basename(headername) + else: + headerbasename = headername + + # List of .proto files that should not be included in the C header file + # even if they are mentioned in the source .proto. + excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto'] + options.exclude + includes = [d for d in f.fdesc.dependency if d not in excludes] + + headerdata = ''.join(f.generate_header(includes, headerbasename, options)) + sourcedata = ''.join(f.generate_source(headerbasename, options)) + + # Check if there were any lines in .options that did not match a member + unmatched = [n for n,o in Globals.separate_options if n not in Globals.matched_namemasks] + if unmatched and not options.quiet: + sys.stderr.write("Following patterns in " + f.optfilename + " did not match any fields: " + + ', '.join(unmatched) + "\n") + if not Globals.verbose_options: + sys.stderr.write("Use protoc --nanopb-out=-v:. to see a list of the field names.\n") + + return {'headername': headername, 'headerdata': headerdata, + 'sourcename': sourcename, 'sourcedata': sourcedata} + +def main_cli(): + '''Main function when invoked directly from the command line.''' + + options, filenames = optparser.parse_args() + + if not filenames: + optparser.print_help() + sys.exit(1) + + if options.quiet: + options.verbose = False + + if options.output_dir and not os.path.exists(options.output_dir): + optparser.print_help() + sys.stderr.write("\noutput_dir does not exist: %s\n" % options.output_dir) + sys.exit(1) + + if options.verbose: + sys.stderr.write('Google Python protobuf library imported from %s, version %s\n' + % (google.protobuf.__file__, google.protobuf.__version__)) + + Globals.verbose_options = options.verbose + for filename in filenames: + results = process_file(filename, None, options) + + base_dir = options.output_dir or '' + to_write = [ + (os.path.join(base_dir, results['headername']), results['headerdata']), + (os.path.join(base_dir, results['sourcename']), results['sourcedata']), + ] + + if not options.quiet: + paths = " and ".join([x[0] for x in to_write]) + sys.stderr.write("Writing to %s\n" % paths) + + for path, data in to_write: + with open(path, 'w') as f: + f.write(data) + +def main_plugin(): + '''Main function when invoked as a protoc plugin.''' + + import io, sys + if sys.platform == "win32": + import os, msvcrt + # Set stdin and stdout to binary mode + msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + + data = io.open(sys.stdin.fileno(), "rb").read() + + request = plugin_pb2.CodeGeneratorRequest.FromString(data) + + try: + # Versions of Python prior to 2.7.3 do not support unicode + # input to shlex.split(). Try to convert to str if possible. + params = str(request.parameter) + except UnicodeEncodeError: + params = request.parameter + + import shlex + args = shlex.split(params) + options, dummy = optparser.parse_args(args) + + Globals.verbose_options = options.verbose + + if options.verbose: + sys.stderr.write('Google Python protobuf library imported from %s, version %s\n' + % (google.protobuf.__file__, google.protobuf.__version__)) + + response = plugin_pb2.CodeGeneratorResponse() + + # Google's protoc does not currently indicate the full path of proto files. + # Instead always add the main file path to the search dirs, that works for + # the common case. + import os.path + options.options_path.append(os.path.dirname(request.file_to_generate[0])) + + # Process any include files first, in order to have them + # available as dependencies + other_files = {} + for fdesc in request.proto_file: + other_files[fdesc.name] = parse_file(fdesc.name, fdesc, options) + + for filename in request.file_to_generate: + for fdesc in request.proto_file: + if fdesc.name == filename: + results = process_file(filename, fdesc, options, other_files) + + f = response.file.add() + f.name = results['headername'] + f.content = results['headerdata'] + + f = response.file.add() + f.name = results['sourcename'] + f.content = results['sourcedata'] + + io.open(sys.stdout.fileno(), "wb").write(response.SerializeToString()) + +if __name__ == '__main__': + # Check if we are running as a plugin under protoc + if 'protoc-gen-' in sys.argv[0] or '--protoc-plugin' in sys.argv: + main_plugin() + else: + main_cli() diff --git a/common/nanopb/generator/proto/Makefile b/common/nanopb/generator/proto/Makefile new file mode 100644 index 0000000..89bfe52 --- /dev/null +++ b/common/nanopb/generator/proto/Makefile @@ -0,0 +1,4 @@ +all: nanopb_pb2.py plugin_pb2.py + +%_pb2.py: %.proto + protoc --python_out=. $< diff --git a/common/nanopb/generator/proto/__init__.py b/common/nanopb/generator/proto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/nanopb/generator/proto/__init__.pyc b/common/nanopb/generator/proto/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1776b382df81f219f3a251689d3e1f257ec5a5d0 GIT binary patch literal 173 zcmZSn%**xlX;w@!0~9a= 128 are escaped. + // TODO(kenton): Base-64 encode? + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default=false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default=false]; +} + + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + optional string java_outer_classname = 8; + + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default=false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default=false]; + + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default=SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + optional bool php_generic_services = 42 [default=false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default=false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default=false]; + + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default=false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default=false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default=false]; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementions still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + optional bool lazy = 5 [default=false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default=false]; + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype +} + +message OneofOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default=false]; + + reserved 5; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default=false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = + 34 [default=IDEMPOTENCY_UNKNOWN]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed=true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed=true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to qux or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed=true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + } +} diff --git a/common/nanopb/generator/proto/nanopb.proto b/common/nanopb/generator/proto/nanopb.proto new file mode 100644 index 0000000..95a57c4 --- /dev/null +++ b/common/nanopb/generator/proto/nanopb.proto @@ -0,0 +1,124 @@ +// Custom options for defining: +// - Maximum size of string/bytes +// - Maximum number of elements in array +// +// These are used by nanopb to generate statically allocable structures +// for memory-limited environments. + +syntax = "proto2"; +import "google/protobuf/descriptor.proto"; + +option java_package = "fi.kapsi.koti.jpa.nanopb"; + +enum FieldType { + FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible. + FT_CALLBACK = 1; // Always generate a callback field. + FT_POINTER = 4; // Always generate a dynamically allocated field. + FT_STATIC = 2; // Generate a static field or raise an exception if not possible. + FT_IGNORE = 3; // Ignore the field completely. + FT_INLINE = 5; // Legacy option, use the separate 'fixed_length' option instead +} + +enum IntSize { + IS_DEFAULT = 0; // Default, 32/64bit based on type in .proto + IS_8 = 8; + IS_16 = 16; + IS_32 = 32; + IS_64 = 64; +} + +enum TypenameMangling { + M_NONE = 0; // Default, no typename mangling + M_STRIP_PACKAGE = 1; // Strip current package name + M_FLATTEN = 2; // Only use last path component +} + +// This is the inner options message, which basically defines options for +// a field. When it is used in message or file scope, it applies to all +// fields. +message NanoPBOptions { + // Allocated size for 'bytes' and 'string' fields. + // For string fields, this should include the space for null terminator. + optional int32 max_size = 1; + + // Maximum length for 'string' fields. Setting this is equivalent + // to setting max_size to a value of length+1. + optional int32 max_length = 14; + + // Allocated number of entries in arrays ('repeated' fields) + optional int32 max_count = 2; + + // Size of integer fields. Can save some memory if you don't need + // full 32 bits for the value. + optional IntSize int_size = 7 [default = IS_DEFAULT]; + + // Force type of field (callback or static allocation) + optional FieldType type = 3 [default = FT_DEFAULT]; + + // Use long names for enums, i.e. EnumName_EnumValue. + optional bool long_names = 4 [default = true]; + + // Add 'packed' attribute to generated structs. + // Note: this cannot be used on CPUs that break on unaligned + // accesses to variables. + optional bool packed_struct = 5 [default = false]; + + // Add 'packed' attribute to generated enums. + optional bool packed_enum = 10 [default = false]; + + // Skip this message + optional bool skip_message = 6 [default = false]; + + // Generate oneof fields as normal optional fields instead of union. + optional bool no_unions = 8 [default = false]; + + // integer type tag for a message + optional uint32 msgid = 9; + + // decode oneof as anonymous union + optional bool anonymous_oneof = 11 [default = false]; + + // Proto3 singular field does not generate a "has_" flag + optional bool proto3 = 12 [default = false]; + + // Generate an enum->string mapping function (can take up lots of space). + optional bool enum_to_string = 13 [default = false]; + + // Generate bytes arrays with fixed length + optional bool fixed_length = 15 [default = false]; + + // Generate repeated field with fixed count + optional bool fixed_count = 16 [default = false]; + + // Mangle long names + optional TypenameMangling mangle_names = 17 [default = M_NONE]; +} + +// Extensions to protoc 'Descriptor' type in order to define options +// inside a .proto file. +// +// Protocol Buffers extension number registry +// -------------------------------- +// Project: Nanopb +// Contact: Petteri Aimonen +// Web site: http://kapsi.fi/~jpa/nanopb +// Extensions: 1010 (all types) +// -------------------------------- + +extend google.protobuf.FileOptions { + optional NanoPBOptions nanopb_fileopt = 1010; +} + +extend google.protobuf.MessageOptions { + optional NanoPBOptions nanopb_msgopt = 1010; +} + +extend google.protobuf.EnumOptions { + optional NanoPBOptions nanopb_enumopt = 1010; +} + +extend google.protobuf.FieldOptions { + optional NanoPBOptions nanopb = 1010; +} + + diff --git a/common/nanopb/generator/proto/nanopb_pb2.py b/common/nanopb/generator/proto/nanopb_pb2.py new file mode 100644 index 0000000..8670759 --- /dev/null +++ b/common/nanopb/generator/proto/nanopb_pb2.py @@ -0,0 +1,351 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: nanopb.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='nanopb.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\xf0\x03\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x12\n\nmax_length\x18\x0e \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x15\n\x06proto3\x18\x0c \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x0e\x65num_to_string\x18\r \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x66ixed_length\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x66ixed_count\x18\x10 \x01(\x08:\x05\x66\x61lse\x12/\n\x0cmangle_names\x18\x11 \x01(\x0e\x32\x11.TypenameMangling:\x06M_NONE*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@*B\n\x10TypenameMangling\x12\n\n\x06M_NONE\x10\x00\x12\x13\n\x0fM_STRIP_PACKAGE\x10\x01\x12\r\n\tM_FLATTEN\x10\x02:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb') + , + dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,]) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +_FIELDTYPE = _descriptor.EnumDescriptor( + name='FieldType', + full_name='FieldType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='FT_DEFAULT', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FT_CALLBACK', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FT_POINTER', index=2, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FT_STATIC', index=3, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FT_IGNORE', index=4, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FT_INLINE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=549, + serialized_end=654, +) +_sym_db.RegisterEnumDescriptor(_FIELDTYPE) + +FieldType = enum_type_wrapper.EnumTypeWrapper(_FIELDTYPE) +_INTSIZE = _descriptor.EnumDescriptor( + name='IntSize', + full_name='IntSize', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='IS_DEFAULT', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='IS_8', index=1, number=8, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='IS_16', index=2, number=16, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='IS_32', index=3, number=32, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='IS_64', index=4, number=64, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=656, + serialized_end=724, +) +_sym_db.RegisterEnumDescriptor(_INTSIZE) + +IntSize = enum_type_wrapper.EnumTypeWrapper(_INTSIZE) +_TYPENAMEMANGLING = _descriptor.EnumDescriptor( + name='TypenameMangling', + full_name='TypenameMangling', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='M_NONE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='M_STRIP_PACKAGE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='M_FLATTEN', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=726, + serialized_end=792, +) +_sym_db.RegisterEnumDescriptor(_TYPENAMEMANGLING) + +TypenameMangling = enum_type_wrapper.EnumTypeWrapper(_TYPENAMEMANGLING) +FT_DEFAULT = 0 +FT_CALLBACK = 1 +FT_POINTER = 4 +FT_STATIC = 2 +FT_IGNORE = 3 +FT_INLINE = 5 +IS_DEFAULT = 0 +IS_8 = 8 +IS_16 = 16 +IS_32 = 32 +IS_64 = 64 +M_NONE = 0 +M_STRIP_PACKAGE = 1 +M_FLATTEN = 2 + +NANOPB_FILEOPT_FIELD_NUMBER = 1010 +nanopb_fileopt = _descriptor.FieldDescriptor( + name='nanopb_fileopt', full_name='nanopb_fileopt', index=0, + number=1010, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=True, extension_scope=None, + options=None) +NANOPB_MSGOPT_FIELD_NUMBER = 1010 +nanopb_msgopt = _descriptor.FieldDescriptor( + name='nanopb_msgopt', full_name='nanopb_msgopt', index=1, + number=1010, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=True, extension_scope=None, + options=None) +NANOPB_ENUMOPT_FIELD_NUMBER = 1010 +nanopb_enumopt = _descriptor.FieldDescriptor( + name='nanopb_enumopt', full_name='nanopb_enumopt', index=2, + number=1010, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=True, extension_scope=None, + options=None) +NANOPB_FIELD_NUMBER = 1010 +nanopb = _descriptor.FieldDescriptor( + name='nanopb', full_name='nanopb', index=3, + number=1010, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=True, extension_scope=None, + options=None) + + +_NANOPBOPTIONS = _descriptor.Descriptor( + name='NanoPBOptions', + full_name='NanoPBOptions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='max_size', full_name='NanoPBOptions.max_size', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='max_length', full_name='NanoPBOptions.max_length', index=1, + number=14, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='max_count', full_name='NanoPBOptions.max_count', index=2, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='int_size', full_name='NanoPBOptions.int_size', index=3, + number=7, type=14, cpp_type=8, label=1, + has_default_value=True, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='type', full_name='NanoPBOptions.type', index=4, + number=3, type=14, cpp_type=8, label=1, + has_default_value=True, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='long_names', full_name='NanoPBOptions.long_names', index=5, + number=4, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=True, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='packed_struct', full_name='NanoPBOptions.packed_struct', index=6, + number=5, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='packed_enum', full_name='NanoPBOptions.packed_enum', index=7, + number=10, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='skip_message', full_name='NanoPBOptions.skip_message', index=8, + number=6, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='no_unions', full_name='NanoPBOptions.no_unions', index=9, + number=8, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='msgid', full_name='NanoPBOptions.msgid', index=10, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='anonymous_oneof', full_name='NanoPBOptions.anonymous_oneof', index=11, + number=11, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='proto3', full_name='NanoPBOptions.proto3', index=12, + number=12, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='enum_to_string', full_name='NanoPBOptions.enum_to_string', index=13, + number=13, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='fixed_length', full_name='NanoPBOptions.fixed_length', index=14, + number=15, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='fixed_count', full_name='NanoPBOptions.fixed_count', index=15, + number=16, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mangle_names', full_name='NanoPBOptions.mangle_names', index=16, + number=17, type=14, cpp_type=8, label=1, + has_default_value=True, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=51, + serialized_end=547, +) + +_NANOPBOPTIONS.fields_by_name['int_size'].enum_type = _INTSIZE +_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE +_NANOPBOPTIONS.fields_by_name['mangle_names'].enum_type = _TYPENAMEMANGLING +DESCRIPTOR.message_types_by_name['NanoPBOptions'] = _NANOPBOPTIONS +DESCRIPTOR.enum_types_by_name['FieldType'] = _FIELDTYPE +DESCRIPTOR.enum_types_by_name['IntSize'] = _INTSIZE +DESCRIPTOR.enum_types_by_name['TypenameMangling'] = _TYPENAMEMANGLING +DESCRIPTOR.extensions_by_name['nanopb_fileopt'] = nanopb_fileopt +DESCRIPTOR.extensions_by_name['nanopb_msgopt'] = nanopb_msgopt +DESCRIPTOR.extensions_by_name['nanopb_enumopt'] = nanopb_enumopt +DESCRIPTOR.extensions_by_name['nanopb'] = nanopb + +NanoPBOptions = _reflection.GeneratedProtocolMessageType('NanoPBOptions', (_message.Message,), dict( + DESCRIPTOR = _NANOPBOPTIONS, + __module__ = 'nanopb_pb2' + # @@protoc_insertion_point(class_scope:NanoPBOptions) + )) +_sym_db.RegisterMessage(NanoPBOptions) + +nanopb_fileopt.message_type = _NANOPBOPTIONS +google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt) +nanopb_msgopt.message_type = _NANOPBOPTIONS +google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt) +nanopb_enumopt.message_type = _NANOPBOPTIONS +google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(nanopb_enumopt) +nanopb.message_type = _NANOPBOPTIONS +google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nanopb) + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\030fi.kapsi.koti.jpa.nanopb')) +# @@protoc_insertion_point(module_scope) diff --git a/common/nanopb/generator/proto/nanopb_pb2.pyc b/common/nanopb/generator/proto/nanopb_pb2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02862d75e59956f7cb27aef778e47d87bbd89721 GIT binary patch literal 8955 zcmds5TX);W5nhs#EJCD2(YesqxN)2~PE5tJqBx4{SQkoBEKv%?#0i=f1qqN|ngmz^ zvaK||I(_ZQkL&3_=zC9k`rLjq3y>fw#c|4$hg#Mevon})ZacGZ>R(yy-~VWSSrg%( z5Ag3@{QBR{3Sr}KLbQZ1gm8ptCWM_7XY7=CC`9+FuqVVfLUfA4o}>pO$uCTaR!X!d zgfSr!q~MfjO^WuEFit6Yn(1j_q!pcJS`)^MqBW*7!pJImhUr;h%!-7Q70o&E6j(XN z>hb2mJ0+TVVP}M$751#K=Y$QRd12>;1Itc}r!fBo;mnKXY0*eP%cOByI62Y8CUaTE zi>w0cOTxzbGDW~Hkc53k5C(RDaaP#pC>r*8UN5lNMOvY^FZK$HU1Bk;CyD)x#a?Bx z%O{Jy#$qWJgYZe(uCN&Nz%~eWxi6WKHx?i(zo;<$LS*i9Bw zaa=lC>|GX9aa_)Ee-F<%x2w7)701TQ5F)a@I> zKv_ZtRriiCP;ZOE0N9c+P+H5vKy`tO0)vLP`CU}ahr%dwu#kToy1N`Kti6)?P}rz~ zRbj6QdtKNY^txRV4r*kRt9Ognk9bwSZ3_ow@^QbmpNcsH#R9CGF|2!xg%w!PiK8?w zEL0q@-i=}HFcwx|soabU3uOze_hMMPjD;0g$oCliy2U6cWn`+%C|KiVt>V8IGiIN~ zK8Yn1p+-Vc9!MyjhZ33;_OS^?x(5?V9azJo<%@7Vl)ENRm z%}96c+3z`4u~fV@jv&d#=NkPL_-Ms zD_(!gtGfDr&DV(>e@pz1_kYhT?k#`d>(L)^J<1s?!oj6)MKnJU_I+{2yiNDvkiMvB z+@KWyk)rX+Y0<+iWna;W2whjju_j_Sne@yMU0P`fon2-INTsR&3k+&*b&YwA>sRuzSzDY ziKj^xzb`}D!YPGrxez&&J>B>h|;4G95_OF+{$Je(&JhqM^+T6Oo;99QNsV+1e*Xde; z*Tp+t;Dy^}r@C0|90k)*e!FG0tG0D#lF;zmH#P}^jm_c##x_xU@Rpn;Ryml$+Oh)a z-cYs^?YK41c9_;dil4|8o#NJWL76kp<{Y-o;Hcx6kGoc<<8&2E1Iu>&T32=u8?|=| zdu_+}t%fo`Afc{PZ#lIR7dhfC}&^IFkO68(2^Hk);*`io5T0rPY#OIW~0q_n=eDsN5=DXD>B8uhDW; zeyfM|g}z@(;?;kqv}_sWu)ns~Ay52#PMdC9PfQrqNEzaT~#d!YuF2 zYiZi6d53OLNb=U}+O%{7_2Mb)%q~tBx82|XidMAk19PLax%%l&CI6Z>K|wF1SVk*u zN~dL4u(P6VR(eteO>22>!{i_pCLlY#G7)qSo&0$%OYwozKImFdm}KT;-D>$x{;W0= zavk@uUC`pZb6UoKC_84D$--2eS1^ZwKXj_>NZ;N! z_hIzvRta{)&RuhJXSGr(m2=6Jk~XVOhFO;_$Lj?7^F?(y)Iq@EKq0oA@DvojqY9o` zoGlI&G?kd{|QwCt)j@eDgJ=F#E?lpmr>wS@kqHT6MbI`Va~_fvkhtL@=XXj7m~cGmo@|WhrUoNNTCd#;86c zN|k4i;_8%SK|n3L=ApMr7e|DLL6E~+OY$yA`7Kn-zma|t9zFpaTXmw@i=h+1&h`#~{5$C? z;JP8d!@`b)bsQcCNnz$J);b-IgQSeHi7l(@v;vx#4=mrbow{|{3QW!`kDAVkA$;GD%R4i5|mAS_jqFUO}CGwU>1e0D0D zX#PvXlEsL{nd{Fvzi_Oi>dulXfkWIIg8s|L%5%eJ6QbF8j0q7-QX%>I5k-6sC>{NY zc#L^{CdY4JM*8PQln(GEUC;Qa#fGPU=A@S>1)RzFIQ7qth{xF+uHJ+_CR{z9q>ACn zl`Q{qrL)3<_{y;Tx@u`0dM4T<@@N$9oPMXg;Ty$pKIjF!?i&m~MN#Tu7s%=%# z&Z!Ue6qsFHEbtap4&Q=&d6V9_OdX4gb)$5!j+tE9)0s5Qwr3yWnqo2;9&g-*+4hs? z(A6?@1?XD1TPvdAF@+=gB}(9+J>`22kfiSBozE zIv)jU*U>#ur(?+pGW%D4of|qu#2mWw>s-F{&W380JReBPw5!1z*jHwlwilROYq)$c z(Ko{6j|A#6bSc^B8}|ve0%~Hq(~!trcaYEZTEgkIj)?aeP2`vWCCl90 zF70eozSu7fXdhBVF{CXTM)%b>lg_2Z;ldU1VB09^mm$UD!X$m=)!owWYIzG+!Y%zx zuyi(`8j?;&NvG4QU!>&~T3(~&3N5eGLh;hC(sGTKw`h4AOTZm%wY;~#2HST^d;1mT zgIWG`cdevzW8m9L%u~wuCVeJwP%8ME(65s&?p#XO?!nfuDt&nfuLOt@q4!9LTUBHf z0vZ~l-y$X-ie4%?Rc4ump=^7ve85|3YMIp|zF6sWrh*r-#Am7>u>%?w4l<&S@Zfed zV*An*?=AJ!@7VkF(O>gg;f0lQ%9R?@93orR0{wk5fl?pUTqvP05`&Hp6=8VO#VUC5>y`KkU#fd~3+)z9uw zckx~Hp-kdRBG>;(Wm36RIx)pRndDp|n~bO_Jmq=+hy9yLDlO?`7J8mn%k#ZGD6Mdh zU11YhUr1!IX4tCdqI\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\tB,\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtos') + , + dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,]) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_CODEGENERATORREQUEST = _descriptor.Descriptor( + name='CodeGeneratorRequest', + full_name='google.protobuf.compiler.CodeGeneratorRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='file_to_generate', full_name='google.protobuf.compiler.CodeGeneratorRequest.file_to_generate', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='parameter', full_name='google.protobuf.compiler.CodeGeneratorRequest.parameter', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='proto_file', full_name='google.protobuf.compiler.CodeGeneratorRequest.proto_file', index=2, + number=15, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=76, + serialized_end=201, +) + + +_CODEGENERATORRESPONSE_FILE = _descriptor.Descriptor( + name='File', + full_name='google.protobuf.compiler.CodeGeneratorResponse.File', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='insertion_point', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.content', index=2, + number=15, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=312, + serialized_end=374, +) + +_CODEGENERATORRESPONSE = _descriptor.Descriptor( + name='CodeGeneratorResponse', + full_name='google.protobuf.compiler.CodeGeneratorResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='error', full_name='google.protobuf.compiler.CodeGeneratorResponse.error', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='file', full_name='google.protobuf.compiler.CodeGeneratorResponse.file', index=1, + number=15, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_CODEGENERATORRESPONSE_FILE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=204, + serialized_end=374, +) + +_CODEGENERATORREQUEST.fields_by_name['proto_file'].message_type = google_dot_protobuf_dot_descriptor__pb2._FILEDESCRIPTORPROTO +_CODEGENERATORRESPONSE_FILE.containing_type = _CODEGENERATORRESPONSE +_CODEGENERATORRESPONSE.fields_by_name['file'].message_type = _CODEGENERATORRESPONSE_FILE +DESCRIPTOR.message_types_by_name['CodeGeneratorRequest'] = _CODEGENERATORREQUEST +DESCRIPTOR.message_types_by_name['CodeGeneratorResponse'] = _CODEGENERATORRESPONSE + +CodeGeneratorRequest = _reflection.GeneratedProtocolMessageType('CodeGeneratorRequest', (_message.Message,), dict( + DESCRIPTOR = _CODEGENERATORREQUEST, + __module__ = 'plugin_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) + )) +_sym_db.RegisterMessage(CodeGeneratorRequest) + +CodeGeneratorResponse = _reflection.GeneratedProtocolMessageType('CodeGeneratorResponse', (_message.Message,), dict( + + File = _reflection.GeneratedProtocolMessageType('File', (_message.Message,), dict( + DESCRIPTOR = _CODEGENERATORRESPONSE_FILE, + __module__ = 'plugin_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) + )) + , + DESCRIPTOR = _CODEGENERATORRESPONSE, + __module__ = 'plugin_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) + )) +_sym_db.RegisterMessage(CodeGeneratorResponse) +_sym_db.RegisterMessage(CodeGeneratorResponse.File) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\034com.google.protobuf.compilerB\014PluginProtos')) +# @@protoc_insertion_point(module_scope) diff --git a/common/nanopb/generator/proto/plugin_pb2.pyc b/common/nanopb/generator/proto/plugin_pb2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6738cd753b929d2fb8dd1ade69089dfed8d6dd65 GIT binary patch literal 5188 zcmcgu>2e!I5bl+HL~A*+9Vd}w6~q_oV&LU#)NI(D_@!-%s(Y zej5W2_-{b~Pz8_xEek{j=0q001xOY_jKD7daS6mIO{y6_Fa|*u_D7&P3Kj_%XL<~( z;shzSsR5R)KqM*#$` zOoK#CX5bLjJq5A=t!ZdlC}p&Ytdr210Xa=v7IBJ2%z`)#;tYthWU(mH4l&2`b3jPQ zMWpk*?E;94nu6UQ7 z@E(uv^T;NP6?TFN*ay7+A&(z{xDDcC5Uc2xsVW8noo{0F3G4ak^J0Wy!eHI`-x$4I z2i|4GwO1Ijbw;c_5wiX~d>J+#GlCl&!A*|fTwet5vD){a7s1bX+vl$^f<;Dr&=#I(LWfP7S-1{lpjU= zvaF+;7bIns)XQ<=KlZdNS9W)nwxaKsHj((=J4k7F^Q&^`g;889H)SXjPe%!!iF8zs zgLcyo-MF?~iVyS&6n;DK_G`jh9VImU_LR*a!OBkJ1eI;!1%lR+k;K~4cqv2RX+OMa zbSGMd^+-sj$rJF3OmWC>T@#EtHZBRN>WLqt1I*euuI)>uyr$7n)22i=0$JC76q-#1 zTvG@8wJ30fr@fk|I-5@pNF*<63S{V^$UIJrcT4PQO;E8{{}!QC5$DY)Y6j9UYwbp< z9_`0|AQN_@ItaD*15f$%vL>f1nfPAd|0o4wsbA4XJKv8nQ+$@tbMuB{!j5p|o+pe7 zmw&cr*DzF@X@)rRyS7w%rf5$!P%l?UZYO(W(VEXL=4PhtTbJGjHM2ifyyL zE*&WraNET4)zYw58^~PmMq-CD@$&DMeR>FA#Zjo_%%nXklO#$Il_2igBYnbeJs~{x zW9g~VN`!rG)gGbWnY=wh!RkmpYZrV3Oepeh9QmQ{SXHpc>rtpBE)+YoI>>69d_NbtTX4SfXO*@oKukq zP5Ddudw%GLO;;bpk~6E}%RneS)j8B3VYPZx>=Hrsi_lblKH6;3IBf6NFny^mSu@hY zCwsZ;)Z^IbMTY{fCIdZ6apn6c|wWM72qabh@FZPB?@KK zFp1LFf|T~KR2~pCHNrj)X1f0ety4FoLR0VH(iCD{%p^e+CO$(FJx4 zMM^`BfitGl6Vyk?l-W7&uV7L5k8#kaQPNOjFjlG3kukXbxN)jmM?PFK2agdpY6JeC z2*~-iUfEr9?(ghvJ50Lnek9u1CtN0buMc${PaLJGF46%_k12Iva{aMPsJ>l4Y($z$ z&#iH-4@KLdoYYh`*jduYfI|h!jmYh^5{DiyW?Sz$;8367GI59A0}gdwPKtHYu6Rzn zTv5~4kZII#MWkJ>f4qa4=qcgy1Ac%Mx6RGMTs>~>fNwhIA{lpz%%lqF@8&Aqqc0$*^Ei=$Z`OJg zJTz~&J-X5;I31dOApE*^s0XkkQr~rUI5&{t&<)Fb_Y%BYC@JX1NpAvra=ANRqU3hx zZlE3H{FJ7sr`vlkTb{jwm%6E?RZ3_zi|r$CEm%|OC!5bsWpmaTfAX1vH94A6xR%LT zGgi^c