diff --git a/.gitignore b/.gitignore index 0ec49e6f6..5ab921d31 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,5 @@ Thumbs.db .cproject .idea/* .vagrant - +nanopb* flash.uf2 diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index bb8a53b50..d56cc09f3 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -3,15 +3,10 @@ Import("projenv") import configparser prefsLoc = projenv["PROJECT_DIR"] + "/version.properties" -print(f"Preferences in {prefsLoc}") -try: - config = configparser.RawConfigParser() - config.read(prefsLoc) - version = dict(config.items('VERSION')) - verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"]) -except: - print("Can't read preferences, using 0.0.0") - verStr = "0.0.0" +config = configparser.RawConfigParser() +config.read(prefsLoc) +version = dict(config.items('VERSION')) +verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"]) print(f"Using meshtastic platform-custom.py, firmare version {verStr}") diff --git a/bin/program-release-tbeam.sh b/bin/program-release-tbeam.sh index d83b35622..037431678 100755 --- a/bin/program-release-tbeam.sh +++ b/bin/program-release-tbeam.sh @@ -1,6 +1,6 @@ set -e -source bin/version.sh +VERSION=`bin/buildinfo.py` esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin diff --git a/bin/regen-protos.sh b/bin/regen-protos.sh index 817dc5d24..ce82d3c36 100755 --- a/bin/regen-protos.sh +++ b/bin/regen-protos.sh @@ -2,10 +2,13 @@ set -e -echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1" +echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.4 to be located in the" +echo "meshtastic-device root directory if the following step fails, you should download the correct" +echo "prebuilt binaries for your computer into nanopb-0.4.4" + # the nanopb tool seems to require that the .options file be in the current directory! cd proto -../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto *.proto +../nanopb-0.4.4/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto *.proto echo "Regenerating protobuf documentation - if you see an error message" echo "you can ignore it unless doing a new protobuf release to github." diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 7c76b12b3..2940a5fb6 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -6,15 +6,13 @@ For app cleanup: * DONE make device build always have a valid version * DONE do fixed position bug https://github.com/meshtastic/Meshtastic-device/issues/536 -* check build guide -* generate autodocs -* write devapi user guide +* DONE check build guide +* DONE write devapi user guide * DONE update android code: https://developer.android.com/topic/libraries/view-binding/migration * only do wantReplies once per packet type, if we change network settings force it again * make gpio watch work, use thread and setup -* make hello world example service +* DONE make hello world example service * make python ping command -* make python gpio read a bit cleaner * DONE have python tool check max packet size before sending to device * DONE if request was sent reliably, send reply reliably * DONE require a recent python api to talk to these new device loads @@ -31,9 +29,13 @@ For app cleanup: * DONE move user info into regular data packets (use new app framework) * DONE test that positions, text messages and user info still work * DONE test that position, text messages and user info work properly with new android app and old device code +* do UDP tunnel * fix the RTC drift bug * move python ping functionality into device, reply with rxsnr info * use channels for gpio security https://github.com/meshtastic/Meshtastic-device/issues/104 +* generate autodocs +* update positions and nodeinfos based on packets we just merely witness on the mesh. via isPromsciousPort bool. +* MeshPackets for sending should be reference counted so that API clients would have the option of checking sent status (would allow removing the nasty 30 sec timer in gpio watch sending) For high speed/lots of devices/short range tasks: diff --git a/docs/software/build-instructions.md b/docs/software/build-instructions.md index 7434b3a5c..31008fda0 100644 --- a/docs/software/build-instructions.md +++ b/docs/software/build-instructions.md @@ -1,8 +1,11 @@ # Build instructions -This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode. +This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode. Workflows from building from the GUI or from the commandline are listed below. + +If you encounter any problems, please post a question in [our forum](meshtastic.discourse.group). And when you learn a fix, update these instructions for the next person (i.e. edit this file and send in a [pull-request](https://opensource.com/article/19/7/create-pull-request-github) which we will eagerly merge). ## GUI + 1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information). 2. Install [Python](https://www.python.org/downloads/). 3. Install [Git](https://git-scm.com/downloads). @@ -19,6 +22,7 @@ This project uses the simple PlatformIO build system. PlatformIO is an extension Note - To get a clean build you may have to delete the auto-generated file `./.vscode/c_cpp_properties.json`, close and re-open Visual Studio and WAIT until the file is auto-generated before compiling again. ## Command Line + 1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information). 2. Install [PlatformIO](https://platformio.org/platformio-ide) 3. Download this git repo and cd into it: diff --git a/docs/software/device-api.md b/docs/software/device-api.md index cdf9e1368..933cd7c37 100644 --- a/docs/software/device-api.md +++ b/docs/software/device-api.md @@ -1,4 +1,6 @@ -# Device API +# Bluetooth/serial/TCP protocol API + +(This document describes the protocol for external API clients using our devices. If you are interested in running your own code on the device itself, see the [on-device](plugin-api.md) documentation instead) The Device API is design to have only a simple stream of ToRadio and FromRadio packets and all polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone. diff --git a/docs/software/plugin-api.md b/docs/software/plugin-api.md new file mode 100644 index 000000000..ba544928d --- /dev/null +++ b/docs/software/plugin-api.md @@ -0,0 +1,71 @@ +# Plugin-API + +This is a tutorial on how to write small plugins which run on the device. Plugins are bits regular 'arduino' code that can send and receive packets to other nodes/apps/PCs using our mesh. + +## Key concepts + +All plugins should be subclasses of MeshPlugin. By inheriting from this class and creating an instance of your new plugin your plugin will be automatically registered to receive packets. + +Messages are sent to particular port numbers (similar to UDP networking). Your new plugin should eventually pick its own port number (see below), but at first you can simply use PRIVATE_APP (which is the default). + +Packets can be sent/received either as raw binary structures or as [Protobufs](https://developers.google.com/protocol-buffers). + +### Class heirarchy + +The relevant bits of the class heirarchy are as follows + +* [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly + * [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that receive from a single port number (the normal case) + * [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that are sending/receiving a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin. + +You will typically want to inherit from either SinglePortPlugin (if you are just sending raw bytes) or ProtobufPlugin (if you are sending protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code. + +If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code. + +If you need to send a packet you can call service.sendToMesh with code like this (from the examples): + +``` + MeshPacket *p = allocReply(); + p->to = dest; + + service.sendToMesh(p); +``` + +## Example plugins + +A number of [key services](/src/plugins) are implemented using the plugin API, these plugins are as follows: + +* [TextMessagePlugin](/src/plugins/TextMessagePlugin.h) - receives text messages and displays them on the LCD screen/stores them in the local DB +* [NodeInfoPlugin](/src/plugins/NodeInfoPlugin.h) - receives/sends User information to other nodes so that usernames are available in the databases +* [RemoteHardwarePlugin](/src/plugins/RemoteHardwarePlugin.h) - a plugin that provides easy remote access to device hardware (for things like turning GPIOs on or off). Intended to be a more extensive example and provide a useful feature of its own. See [remote-hardware](remote-hardware.md) for details. +* [ReplyPlugin](/src/plugins/ReplyPlugin.h) - a simple plugin that just replies to any packet it receives (provides a 'ping' service). + +## Getting started + +The easiest way to get started is: + +* [Build and install](build-instructions.md) the standard codebase from github. +* Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from REPLY_APP to PRIVATE_APP. +* Rebuild with your new messaging goodness and install on the device +* Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board "meshtastic --dest 1234 --ping" + +## Picking a port number + +For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application. + +If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range: + +* 0-63 Core Meshtastic use, do not use for third party apps +* 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application +* 256-511 Use one of these portnums for your private applications that you don't want to register publically +* 1024-66559 Are reserved for use by IP tunneling (see FIXME for more information) + +All other values are reserved. + +## How to add custom protocol buffers + +If you would like to use protocol buffers to define the structures you send over the mesh (recommended), here's how to do that. + +* Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example. +* Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it. +* Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic. \ No newline at end of file diff --git a/docs/software/sw-design.md b/docs/software/sw-design.md index 90ebb4d19..4f715dec5 100644 --- a/docs/software/sw-design.md +++ b/docs/software/sw-design.md @@ -1,9 +1,10 @@ This is a mini design doc for developing the meshtastic software. * [Build instructions](build-instructions.md) +* [On device plugin API](plugin-api.md) - a tutorial on how to write small Plugins which run on the device and can message other nodes. * [TODO](TODO.md) - read this if you are looking for things to do (or curious about currently missing features) * Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release. * [Power Management](power.md) * [Mesh algorithm](mesh-alg.md) -* [Device API](device-api.md) and porting guide for new clients (iOS, python, etc...) +* [External client API](device-api.md) and porting guide for new clients (iOS, python, etc...) * TODO: how to port the device code to a new device. diff --git a/lib/nanopb/include/pb.h b/lib/nanopb/include/pb.h index 45504e992..ae687ebc9 100644 --- a/lib/nanopb/include/pb.h +++ b/lib/nanopb/include/pb.h @@ -11,7 +11,7 @@ *****************************************************************/ /* Enable support for dynamically allocated fields */ -#define PB_ENABLE_MALLOC 1 +/* #define PB_ENABLE_MALLOC 1 */ /* Define this if your CPU / compiler combination does not support * unaligned memory access to packed structures. */ @@ -55,7 +55,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.4.1 +#define NANOPB_VERSION nanopb-0.4.4 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -276,17 +276,18 @@ typedef struct pb_field_iter_s pb_field_iter_t; /* This structure is used in auto-generated constants * to specify struct fields. */ -PB_PACKED_STRUCT_START typedef struct pb_msgdesc_s pb_msgdesc_t; struct pb_msgdesc_s { - pb_size_t field_count; const uint32_t *field_info; const pb_msgdesc_t * const * submsg_info; const pb_byte_t *default_value; bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field); -} pb_packed; -PB_PACKED_STRUCT_END + + pb_size_t field_count; + pb_size_t required_field_count; + pb_size_t largest_tag; +}; /* Iterator for message descriptor */ struct pb_field_iter_s { @@ -469,137 +470,181 @@ struct pb_extension_s { }; \ const pb_msgdesc_t structname ## _msg = \ { \ - 0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \ structname ## _field_info, \ structname ## _submsg_info, \ msgname ## _DEFAULT, \ msgname ## _CALLBACK, \ + 0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \ + 0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \ + 0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \ }; \ msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname) #define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1 +#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \ + + (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED) +#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \ + * 0 + tag +/* X-macro for generating the entries in struct_field_info[] array. */ #define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(1, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(2, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(4, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(8, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ + tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) -#define PB_GEN_FIELD_INFO_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) +#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) -#define PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname)) +#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size) +/* X-macro for generating asserts that entries fit in struct_field_info[] array. + * The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(), + * but it is not easily reused because of how macro substitutions work. */ #define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(1, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(2, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(4, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(8, structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) #define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag) + PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ + tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ + PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ + PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) -#define PB_GEN_FIELD_INFO_ASSERT_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) +#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) -#define PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname)) +#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ + PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size) -#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname) -#define PB_DATA_OFFSET_REQUIRED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_SINGULAR(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_OFFSET_OPTIONAL(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_REPEATED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DATA_OFFSET_FIXARRAY(structname, fieldname) offsetof(structname, fieldname) +#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) +#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname) +#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname) -#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SIZE_OFFSET_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SIZE_OFFSET_PTR_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SIZE_OFFSET_CB_ ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname)) -#define PB_SIZE_OFFSET_ONEOF2(structname, fullname, unionname) PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) -#define PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname) -#define PB_SIZE_OFFSET_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname) -#define PB_SIZE_OFFSET_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count) -#define PB_SIZE_OFFSET_FIXARRAY(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname) -#define PB_SIZE_OFFSET_PTR_OPTIONAL(structname, fieldname) 0 -#define PB_SIZE_OFFSET_PTR_REPEATED(structname, fieldname) PB_SIZE_OFFSET_REPEATED(structname, fieldname) -#define PB_SIZE_OFFSET_PTR_FIXARRAY(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_REQUIRED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_SINGULAR(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname) -#define PB_SIZE_OFFSET_CB_OPTIONAL(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_REPEATED(structname, fieldname) 0 -#define PB_SIZE_OFFSET_CB_FIXARRAY(structname, fieldname) 0 +#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname) +#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname) +#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname) +#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname)) +#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) +#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname) +#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname) +#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count) +#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) +#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0 +#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname) +#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) +#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0 +#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0 -#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_ARRAY_SIZE_ ## htype(structname, fieldname) -#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_ARRAY_SIZE_PTR_ ## htype(structname, fieldname) +#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname) +#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname) #define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1 -#define PB_ARRAY_SIZE_REQUIRED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_SINGULAR(structname, fieldname) 1 -#define PB_ARRAY_SIZE_OPTIONAL(structname, fieldname) 1 -#define PB_ARRAY_SIZE_ONEOF(structname, fieldname) 1 -#define PB_ARRAY_SIZE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_ARRAY_SIZE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_ARRAY_SIZE_PTR_REQUIRED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_SINGULAR(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_OPTIONAL(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_ONEOF(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_REPEATED(structname, fieldname) 1 -#define PB_ARRAY_SIZE_PTR_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0]) +#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1 +#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname) +#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname) +#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1 +#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0]) -#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DATA_SIZE_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DATA_SIZE_PTR_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DATA_SIZE_CB_ ## htype(structname, fieldname) -#define PB_DATA_SIZE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_SIZE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0]) -#define PB_DATA_SIZE_PTR_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DATA_SIZE_PTR_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0]) -#define PB_DATA_SIZE_CB_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DATA_SIZE_CB_REPEATED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DATA_SIZE_CB_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname) +#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname) +#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname) +#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0]) +#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) +#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0]) +#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) +#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname) +#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname) #define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple) #define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname @@ -607,37 +652,37 @@ struct pb_extension_s { #define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname #define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \ - PB_SUBMSG_INFO_ ## htype(ltype, structname, fieldname) + PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname) -#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) #define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname)) #define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) -#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE) -#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_BOOL(t) -#define PB_SUBMSG_INFO_BYTES(t) -#define PB_SUBMSG_INFO_DOUBLE(t) -#define PB_SUBMSG_INFO_ENUM(t) -#define PB_SUBMSG_INFO_UENUM(t) -#define PB_SUBMSG_INFO_FIXED32(t) -#define PB_SUBMSG_INFO_FIXED64(t) -#define PB_SUBMSG_INFO_FLOAT(t) -#define PB_SUBMSG_INFO_INT32(t) -#define PB_SUBMSG_INFO_INT64(t) -#define PB_SUBMSG_INFO_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SUBMSG_INFO_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SUBMSG_INFO_SFIXED32(t) -#define PB_SUBMSG_INFO_SFIXED64(t) -#define PB_SUBMSG_INFO_SINT32(t) -#define PB_SUBMSG_INFO_SINT64(t) -#define PB_SUBMSG_INFO_STRING(t) -#define PB_SUBMSG_INFO_UINT32(t) -#define PB_SUBMSG_INFO_UINT64(t) -#define PB_SUBMSG_INFO_EXTENSION(t) -#define PB_SUBMSG_INFO_FIXED_LENGTH_BYTES(t) +#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE) +#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) +#define PB_SI_PB_LTYPE_BOOL(t) +#define PB_SI_PB_LTYPE_BYTES(t) +#define PB_SI_PB_LTYPE_DOUBLE(t) +#define PB_SI_PB_LTYPE_ENUM(t) +#define PB_SI_PB_LTYPE_UENUM(t) +#define PB_SI_PB_LTYPE_FIXED32(t) +#define PB_SI_PB_LTYPE_FIXED64(t) +#define PB_SI_PB_LTYPE_FLOAT(t) +#define PB_SI_PB_LTYPE_INT32(t) +#define PB_SI_PB_LTYPE_INT64(t) +#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t) +#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t) +#define PB_SI_PB_LTYPE_SFIXED32(t) +#define PB_SI_PB_LTYPE_SFIXED64(t) +#define PB_SI_PB_LTYPE_SINT32(t) +#define PB_SI_PB_LTYPE_SINT64(t) +#define PB_SI_PB_LTYPE_STRING(t) +#define PB_SI_PB_LTYPE_UINT32(t) +#define PB_SI_PB_LTYPE_UINT64(t) +#define PB_SI_PB_LTYPE_EXTENSION(t) +#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t) #define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg), /* The field descriptors use a variable width format, with width of either @@ -726,37 +771,37 @@ struct pb_extension_s { * The generator will give explicit size argument when it knows that a message * structure grows beyond 1-word format limits. */ -#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FIELDINFO_WIDTH_ ## atype(htype, ltype) -#define PB_FIELDINFO_WIDTH_STATIC(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype) -#define PB_FIELDINFO_WIDTH_POINTER(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype) -#define PB_FIELDINFO_WIDTH_CALLBACK(htype, ltype) 2 -#define PB_FIELDINFO_WIDTH_REQUIRED(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_SINGULAR(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_OPTIONAL(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_ONEOF(ltype) PB_FIELDINFO_WIDTH_ ## ltype -#define PB_FIELDINFO_WIDTH_REPEATED(ltype) 2 -#define PB_FIELDINFO_WIDTH_FIXARRAY(ltype) 2 -#define PB_FIELDINFO_WIDTH_BOOL 1 -#define PB_FIELDINFO_WIDTH_BYTES 2 -#define PB_FIELDINFO_WIDTH_DOUBLE 1 -#define PB_FIELDINFO_WIDTH_ENUM 1 -#define PB_FIELDINFO_WIDTH_UENUM 1 -#define PB_FIELDINFO_WIDTH_FIXED32 1 -#define PB_FIELDINFO_WIDTH_FIXED64 1 -#define PB_FIELDINFO_WIDTH_FLOAT 1 -#define PB_FIELDINFO_WIDTH_INT32 1 -#define PB_FIELDINFO_WIDTH_INT64 1 -#define PB_FIELDINFO_WIDTH_MESSAGE 2 -#define PB_FIELDINFO_WIDTH_MSG_W_CB 2 -#define PB_FIELDINFO_WIDTH_SFIXED32 1 -#define PB_FIELDINFO_WIDTH_SFIXED64 1 -#define PB_FIELDINFO_WIDTH_SINT32 1 -#define PB_FIELDINFO_WIDTH_SINT64 1 -#define PB_FIELDINFO_WIDTH_STRING 2 -#define PB_FIELDINFO_WIDTH_UINT32 1 -#define PB_FIELDINFO_WIDTH_UINT64 1 -#define PB_FIELDINFO_WIDTH_EXTENSION 1 -#define PB_FIELDINFO_WIDTH_FIXED_LENGTH_BYTES 2 +#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype) +#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype) +#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype) +#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2 +#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype +#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2 +#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2 +#define PB_FI_WIDTH_PB_LTYPE_BOOL 1 +#define PB_FI_WIDTH_PB_LTYPE_BYTES 2 +#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1 +#define PB_FI_WIDTH_PB_LTYPE_ENUM 1 +#define PB_FI_WIDTH_PB_LTYPE_UENUM 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1 +#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1 +#define PB_FI_WIDTH_PB_LTYPE_INT32 1 +#define PB_FI_WIDTH_PB_LTYPE_INT64 1 +#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2 +#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2 +#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1 +#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1 +#define PB_FI_WIDTH_PB_LTYPE_SINT32 1 +#define PB_FI_WIDTH_PB_LTYPE_SINT64 1 +#define PB_FI_WIDTH_PB_LTYPE_STRING 2 +#define PB_FI_WIDTH_PB_LTYPE_UINT32 1 +#define PB_FI_WIDTH_PB_LTYPE_UINT64 1 +#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1 +#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2 /* The mapping from protobuf types to LTYPEs is done using these macros. */ #define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL diff --git a/lib/nanopb/include/pb_common.h b/lib/nanopb/include/pb_common.h index 47fa2c99e..58aa90f76 100644 --- a/lib/nanopb/include/pb_common.h +++ b/lib/nanopb/include/pb_common.h @@ -32,6 +32,10 @@ bool pb_field_iter_next(pb_field_iter_t *iter); * Returns false if no such field exists. */ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); +/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found. + * There can be only one extension range field per message. */ +bool pb_field_iter_find_extension(pb_field_iter_t *iter); + #ifdef PB_VALIDATE_UTF8 /* Validate UTF-8 text string */ bool pb_validate_utf8(const char *s); diff --git a/lib/nanopb/include/pb_decode.h b/lib/nanopb/include/pb_decode.h index b64d95aea..824acd4ea 100644 --- a/lib/nanopb/include/pb_decode.h +++ b/lib/nanopb/include/pb_decode.h @@ -113,6 +113,9 @@ bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_s * pb_decode() returns with an error, the message is already released. */ void pb_release(const pb_msgdesc_t *fields, void *dest_struct); +#else +/* Allocation is not supported, so release is no-op */ +#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct); #endif @@ -121,11 +124,14 @@ void pb_release(const pb_msgdesc_t *fields, void *dest_struct); **************************************/ /* Create an input stream for reading from a memory buffer. + * + * msglen should be the actual length of the message, not the full size of + * allocated buffer. * * Alternatively, you can use a custom stream that reads directly from e.g. * a file or a network socket. */ -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen); /* Function to read from a pb_istream_t. You can use this if you need to * read some custom header data, or to read data in field callbacks. diff --git a/lib/nanopb/include/pb_encode.h b/lib/nanopb/include/pb_encode.h index 88e246a2d..9cff22a4f 100644 --- a/lib/nanopb/include/pb_encode.h +++ b/lib/nanopb/include/pb_encode.h @@ -132,7 +132,7 @@ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); * structure. Call this from the callback before writing out field contents. */ bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field); -/* Encode field header by manually specifing wire type. You need to use this +/* Encode field header by manually specifying wire type. You need to use this * if you want to write out packed arrays from a callback field. */ bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); diff --git a/lib/nanopb/src/pb_common.c b/lib/nanopb/src/pb_common.c index dfc5a05b0..6aee76b1e 100644 --- a/lib/nanopb/src/pb_common.c +++ b/lib/nanopb/src/pb_common.c @@ -9,89 +9,102 @@ static bool load_descriptor_values(pb_field_iter_t *iter) { uint32_t word0; uint32_t data_offset; - uint_least8_t format; int_least8_t size_offset; if (iter->index >= iter->descriptor->field_count) return false; word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - format = word0 & 3; - iter->tag = (pb_size_t)((word0 >> 2) & 0x3F); iter->type = (pb_type_t)((word0 >> 8) & 0xFF); - if (format == 0) + switch(word0 & 3) { - /* 1-word format */ - iter->array_size = 1; - size_offset = (int_least8_t)((word0 >> 24) & 0x0F); - data_offset = (word0 >> 16) & 0xFF; - iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F); - } - else if (format == 1) - { - /* 2-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + case 0: { + /* 1-word format */ + iter->array_size = 1; + iter->tag = (pb_size_t)((word0 >> 2) & 0x3F); + size_offset = (int_least8_t)((word0 >> 24) & 0x0F); + data_offset = (word0 >> 16) & 0xFF; + iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F); + break; + } - iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF); - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6)); - size_offset = (int_least8_t)((word0 >> 28) & 0x0F); - data_offset = word1 & 0xFFFF; - iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF); - } - else if (format == 2) - { - /* 4-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + case 1: { + /* 2-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - iter->array_size = (pb_size_t)(word0 >> 16); - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; - } - else - { - /* 8-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); - uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]); + iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF); + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6)); + size_offset = (int_least8_t)((word0 >> 28) & 0x0F); + data_offset = word1 & 0xFFFF; + iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF); + break; + } - iter->array_size = (pb_size_t)word4; - iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; + case 2: { + /* 4-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); + uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + + iter->array_size = (pb_size_t)(word0 >> 16); + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); + size_offset = (int_least8_t)(word1 & 0xFF); + data_offset = word2; + iter->data_size = (pb_size_t)word3; + break; + } + + default: { + /* 8-word format */ + uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); + uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); + uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); + uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]); + + iter->array_size = (pb_size_t)word4; + iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); + size_offset = (int_least8_t)(word1 & 0xFF); + data_offset = word2; + iter->data_size = (pb_size_t)word3; + break; + } } - iter->pField = (char*)iter->message + data_offset; - - if (size_offset) - { - iter->pSize = (char*)iter->pField - size_offset; - } - else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && - (PB_ATYPE(iter->type) == PB_ATYPE_STATIC || - PB_ATYPE(iter->type) == PB_ATYPE_POINTER)) - { - /* Fixed count array */ - iter->pSize = &iter->array_size; - } - else + if (!iter->message) { + /* Avoid doing arithmetic on null pointers, it is undefined */ + iter->pField = NULL; iter->pSize = NULL; } - - if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL) - { - iter->pData = *(void**)iter->pField; - } else { - iter->pData = iter->pField; + iter->pField = (char*)iter->message + data_offset; + + if (size_offset) + { + iter->pSize = (char*)iter->pField - size_offset; + } + else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && + (PB_ATYPE(iter->type) == PB_ATYPE_STATIC || + PB_ATYPE(iter->type) == PB_ATYPE_POINTER)) + { + /* Fixed count array */ + iter->pSize = &iter->array_size; + } + else + { + iter->pSize = NULL; + } + + if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL) + { + iter->pData = *(void**)iter->pField; + } + else + { + iter->pData = iter->pField; + } } if (PB_LTYPE_IS_SUBMSG(iter->type)) @@ -130,17 +143,13 @@ static void advance_iterator(pb_field_iter_t *iter) pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF; pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3)); + /* Add to fields. + * The cast to pb_size_t is needed to avoid -Wconversion warning. + * Because the data is is constants from generator, there is no danger of overflow. + */ iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len); - - if (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED) - { - iter->required_field_index++; - } - - if (PB_LTYPE_IS_SUBMSG(prev_type)) - { - iter->submessage_index++; - } + iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)); + iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type)); } } @@ -189,11 +198,23 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) { return true; /* Nothing to do, correct field already. */ } + else if (tag > iter->descriptor->largest_tag) + { + return false; + } else { pb_size_t start = iter->index; uint32_t fieldinfo; + if (tag < iter->tag) + { + /* Fields are in tag number order, so we know that tag is between + * 0 and our start position. Setting index to end forces + * advance_iterator() call below to restart from beginning. */ + iter->index = iter->descriptor->field_count; + } + do { /* Advance iterator but don't load values yet */ @@ -222,6 +243,37 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) } } +bool pb_field_iter_find_extension(pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION) + { + return true; + } + else + { + pb_size_t start = iter->index; + uint32_t fieldinfo; + + do + { + /* Advance iterator but don't load values yet */ + advance_iterator(iter); + + /* Do fast check for field type */ + fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); + + if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION) + { + return load_descriptor_values(iter); + } + } while (iter->index != start); + + /* Searched all the way back to start, and found nothing. */ + (void)load_descriptor_values(iter); + return false; + } +} + static void *pb_const_cast(const void *p) { /* Note: this casts away const, in order to use the common field iterator diff --git a/lib/nanopb/src/pb_decode.c b/lib/nanopb/src/pb_decode.c index f936412b7..28f6b5799 100644 --- a/lib/nanopb/src/pb_decode.c +++ b/lib/nanopb/src/pb_decode.c @@ -24,19 +24,17 @@ static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); -static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field); +static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension); +static bool pb_field_set_to_default(pb_field_iter_t *field); static bool pb_message_set_to_defaults(pb_field_iter_t *iter); static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field); static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field); @@ -59,6 +57,8 @@ static void pb_release_single_field(pb_field_iter_t *field); #define pb_uint64_t uint64_t #endif +#define PB_WT_PACKED ((pb_wire_type_t)0xFF) + typedef struct { uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32]; } pb_fields_seen_t; @@ -139,7 +139,7 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) return true; } -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen) { pb_istream_t stream; /* Cast away the const from buf without a compiler error. We are @@ -156,7 +156,7 @@ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) #endif state.c_state = buf; stream.state = state.state; - stream.bytes_left = bufsize; + stream.bytes_left = msglen; #ifndef PB_NO_ERRMSG stream.errmsg = NULL; #endif @@ -205,8 +205,10 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d { /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; - - if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + bool valid_extension = ((byte & 0x7F) == 0x00 || + ((result >> 31) != 0 && byte == sign_extension)); + + if (bitpos >= 64 || !valid_extension) { PB_RETURN_ERROR(stream, "varint overflow"); } @@ -388,61 +390,70 @@ bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *s * Decode a single field * *************************/ -static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field) +static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) { switch (PB_LTYPE(field->type)) { case PB_LTYPE_BOOL: - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - return wire_type == PB_WT_VARINT; + if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); - case PB_LTYPE_FIXED32: - return wire_type == PB_WT_32BIT; - - case PB_LTYPE_FIXED64: - return wire_type == PB_WT_64BIT; - - case PB_LTYPE_BYTES: - case PB_LTYPE_STRING: - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_SUBMSG_W_CB: - case PB_LTYPE_FIXED_LENGTH_BYTES: - return wire_type == PB_WT_STRING; - - default: - return false; - } -} - -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field) -{ - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: return pb_dec_bool(stream, field); case PB_LTYPE_VARINT: case PB_LTYPE_UVARINT: case PB_LTYPE_SVARINT: + if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_varint(stream, field); case PB_LTYPE_FIXED32: + if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + + return pb_decode_fixed32(stream, field->pData); + case PB_LTYPE_FIXED64: - return pb_dec_fixed(stream, field); + if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED) + PB_RETURN_ERROR(stream, "wrong wire type"); + +#ifdef PB_CONVERT_DOUBLE_FLOAT + if (field->data_size == sizeof(float)) + { + return pb_decode_double_as_float(stream, (float*)field->pData); + } +#endif + +#ifdef PB_WITHOUT_64BIT + PB_RETURN_ERROR(stream, "invalid data_size"); +#else + return pb_decode_fixed64(stream, field->pData); +#endif case PB_LTYPE_BYTES: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_bytes(stream, field); case PB_LTYPE_STRING: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_string(stream, field); case PB_LTYPE_SUBMESSAGE: case PB_LTYPE_SUBMSG_W_CB: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_submessage(stream, field); case PB_LTYPE_FIXED_LENGTH_BYTES: + if (wire_type != PB_WT_STRING) + PB_RETURN_ERROR(stream, "wrong wire type"); + return pb_dec_fixed_length_bytes(stream, field); default: @@ -455,18 +466,12 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t switch (PB_HTYPE(field->type)) { case PB_HTYPE_REQUIRED: - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); case PB_HTYPE_OPTIONAL: - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (field->pSize != NULL) *(bool*)field->pSize = true; - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); case PB_HTYPE_REPEATED: if (wire_type == PB_WT_STRING @@ -483,7 +488,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t while (substream.bytes_left > 0 && *size < field->array_size) { - if (!decode_basic_field(&substream, field)) + if (!decode_basic_field(&substream, PB_WT_PACKED, field)) { status = false; break; @@ -505,18 +510,15 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t pb_size_t *size = (pb_size_t*)field->pSize; field->pData = (char*)field->pField + field->data_size * (*size); - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if ((*size)++ >= field->array_size) PB_RETURN_ERROR(stream, "array overflow"); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } case PB_HTYPE_ONEOF: - *(pb_size_t*)field->pSize = field->tag; - if (PB_LTYPE_IS_SUBMSG(field->type)) + if (PB_LTYPE_IS_SUBMSG(field->type) && + *(pb_size_t*)field->pSize != field->tag) { /* We memset to zero so that any callbacks are set to NULL. * This is because the callbacks might otherwise have values @@ -526,12 +528,14 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t * that can set the fields before submessage is decoded. * pb_dec_submessage() will set any default values. */ memset(field->pData, 0, (size_t)field->data_size); + + /* Set default values for the submessage fields. */ + if (!pb_field_set_to_default(field)) + PB_RETURN_ERROR(stream, "failed to set defaults"); } + *(pb_size_t*)field->pSize = field->tag; - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); default: PB_RETURN_ERROR(stream, "invalid field type"); @@ -599,14 +603,8 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *field) else if (PB_LTYPE_IS_SUBMSG(field->type)) { /* We memset to zero so that any callbacks are set to NULL. - * Then set any default values. */ - pb_field_iter_t submsg_iter; + * Default values will be set by pb_dec_submessage(). */ memset(pItem, 0, field->data_size); - - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, pItem)) - { - (void)pb_message_set_to_defaults(&submsg_iter); - } } } #endif @@ -623,9 +621,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ case PB_HTYPE_REQUIRED: case PB_HTYPE_OPTIONAL: case PB_HTYPE_ONEOF: - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL) { /* Duplicate field, have to release the old allocation first. */ @@ -643,7 +638,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { /* pb_dec_string and pb_dec_bytes handle allocation themselves */ field->pData = field->pField; - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } else { @@ -652,7 +647,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ field->pData = *(void**)field->pField; initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } case PB_HTYPE_REPEATED: @@ -700,7 +695,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ /* Decode the array entry */ field->pData = *(char**)field->pField + field->data_size * (*size); initialize_pointer_field(field->pData, field); - if (!decode_basic_field(&substream, field)) + if (!decode_basic_field(&substream, PB_WT_PACKED, field)) { status = false; break; @@ -721,16 +716,13 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ if (*size == PB_SIZE_MAX) PB_RETURN_ERROR(stream, "too many array entries"); - if (!check_wire_type(wire_type, field)) - PB_RETURN_ERROR(stream, "wrong wire type"); - if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1))) return false; field->pData = *(char**)field->pField + field->data_size * (*size); (*size)++; initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, field); + return decode_basic_field(stream, wire_type, field); } default: @@ -821,7 +813,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, if (!pb_field_iter_begin_extension(&iter, extension)) PB_RETURN_ERROR(stream, "invalid extension"); - if (iter.tag != tag) + if (iter.tag != tag || !iter.message) return true; extension->found = true; @@ -831,9 +823,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, /* Try to decode an unknown field as an extension field. Tries each extension * decoder in turn, until one of them handles the field or loop ends. */ static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) + uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension) { - pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; while (extension != NULL && pos == stream->bytes_left) @@ -853,22 +844,6 @@ static bool checkreturn decode_extension(pb_istream_t *stream, return true; } -/* Step through the iterator until an extension field is found or until all - * entries have been checked. There can be only one extension field per - * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iter_t *iter) -{ - pb_size_t start = iter->index; - - do { - if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION) - return true; - (void)pb_field_iter_next(iter); - } while (iter->index != start); - - return false; -} - /* Initialize message fields to default values, recursively */ static bool pb_field_set_to_default(pb_field_iter_t *field) { @@ -910,9 +885,14 @@ static bool pb_field_set_to_default(pb_field_iter_t *field) if (init_data) { - if (PB_LTYPE_IS_SUBMSG(field->type)) + if (PB_LTYPE_IS_SUBMSG(field->type) && + (field->submsg_desc->default_value != NULL || + field->submsg_desc->field_callback != NULL || + field->submsg_desc->submsg_info[0] != NULL)) { - /* Initialize submessage to defaults */ + /* Initialize submessage to defaults. + * Only needed if it has default values + * or callback/submessage fields. */ pb_field_iter_t submsg_iter; if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) { @@ -989,6 +969,7 @@ static bool pb_message_set_to_defaults(pb_field_iter_t *iter) static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags) { uint32_t extension_range_start = 0; + pb_extension_t *extensions = NULL; /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed * count field. This can only handle _one_ repeated fixed count field that @@ -1040,25 +1021,31 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION) { /* No match found, check if it matches an extension. */ + if (extension_range_start == 0) + { + if (pb_field_iter_find_extension(&iter)) + { + extensions = *(pb_extension_t* const *)iter.pData; + extension_range_start = iter.tag; + } + + if (!extensions) + { + extension_range_start = (uint32_t)-1; + } + } + if (tag >= extension_range_start) { - if (!find_extension_field(&iter)) - extension_range_start = (uint32_t)-1; - else - extension_range_start = iter.tag; + size_t pos = stream->bytes_left; - if (tag >= extension_range_start) + if (!decode_extension(stream, tag, wire_type, extensions)) + return false; + + if (pos != stream->bytes_left) { - size_t pos = stream->bytes_left; - - if (!decode_extension(stream, tag, wire_type, &iter)) - return false; - - if (pos != stream->bytes_left) - { - /* The field was handled */ - continue; - } + /* The field was handled */ + continue; } } @@ -1112,27 +1099,15 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t /* Check that all required fields were present. */ { - /* First figure out the number of required fields by - * seeking to the end of the field array. Usually we - * are already close to end after decoding. - */ - pb_size_t req_field_count; - pb_type_t last_type; - pb_size_t i; - do { - req_field_count = iter.required_field_index; - last_type = iter.type; - } while (pb_field_iter_next(&iter)); - - /* Fixup if last field was also required. */ - if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.tag != 0) - req_field_count++; - - if (req_field_count > PB_MAX_REQUIRED_FIELDS) - req_field_count = PB_MAX_REQUIRED_FIELDS; + pb_size_t req_field_count = iter.descriptor->required_field_count; if (req_field_count > 0) { + pb_size_t i; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + /* Check the whole words */ for (i = 0; i < (req_field_count >> 5); i++) { @@ -1277,7 +1252,7 @@ static void pb_release_single_field(pb_field_iter_t *field) if (field->pData) { - while (count--) + for (; count > 0; count--) { pb_release(field->submsg_desc, field->pData); field->pData = (char*)field->pData + field->data_size; @@ -1294,7 +1269,7 @@ static void pb_release_single_field(pb_field_iter_t *field) /* Release entries in repeated string or bytes array */ void **pItem = *(void***)field->pField; pb_size_t count = *(pb_size_t*)field->pSize; - while (count--) + for (; count > 0; count--) { pb_free(*pItem); *pItem++ = NULL; @@ -1454,7 +1429,7 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_ /* See issue 97: Google's C++ protobuf allows negative varint values to * be cast as int32_t, instead of the int64_t that should be used when - * encoding. Previous nanopb versions had a bug in encoding. In order to + * encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to * not break decoding of such messages, we cast <=32 bit fields to * int32_t first to get the sign correct. */ @@ -1483,31 +1458,6 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_ } } -static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field) -{ -#ifdef PB_CONVERT_DOUBLE_FLOAT - if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - return pb_decode_double_as_float(stream, (float*)field->pData); - } -#endif - - if (field->data_size == sizeof(uint32_t)) - { - return pb_decode_fixed32(stream, field->pData); - } -#ifndef PB_WITHOUT_64BIT - else if (field->data_size == sizeof(uint64_t)) - { - return pb_decode_fixed64(stream, field->pData); - } -#endif - else - { - PB_RETURN_ERROR(stream, "invalid data_size"); - } -} - static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field) { uint32_t size; @@ -1601,6 +1551,7 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field) { bool status = true; + bool submsg_consumed = false; pb_istream_t substream; if (!pb_make_string_substream(stream, &substream)) @@ -1609,19 +1560,6 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i if (field->submsg_desc == NULL) PB_RETURN_ERROR(stream, "invalid field descriptor"); - /* New array entries need to be initialized, while required and optional - * submessages have already been initialized in the top-level pb_decode. */ - if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED || - PB_HTYPE(field->type) == PB_HTYPE_ONEOF) - { - pb_field_iter_t submsg_iter; - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) - { - if (!pb_message_set_to_defaults(&submsg_iter)) - PB_RETURN_ERROR(stream, "failed to set defaults"); - } - } - /* Submessages can have a separate message-level callback that is called * before decoding the message. Typically it is used to set callback fields * inside oneofs. */ @@ -1632,13 +1570,28 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i if (callback->funcs.decode) { status = callback->funcs.decode(&substream, field, &callback->arg); + + if (substream.bytes_left == 0) + { + submsg_consumed = true; + } } } /* Now decode the submessage contents */ - if (status) + if (status && !submsg_consumed) { - status = pb_decode_inner(&substream, field->submsg_desc, field->pData, 0); + unsigned int flags = 0; + + /* Static required/optional fields are already initialized by top-level + * pb_decode(), no need to initialize them again. */ + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_HTYPE(field->type) != PB_HTYPE_REPEATED) + { + flags = PB_DECODE_NOINIT; + } + + status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags); } if (!pb_close_string_substream(stream, &substream)) @@ -1692,37 +1645,41 @@ bool pb_decode_double_as_float(pb_istream_t *stream, float *dest) { /* Special value */ exponent = 128; - } - else if (exponent > 127) - { - /* Too large, convert to infinity */ - exponent = 128; - mantissa = 0; - } - else if (exponent < -150) - { - /* Too small, convert to zero */ - exponent = -127; - mantissa = 0; - } - else if (exponent < -126) - { - /* Denormalized */ - mantissa |= 0x1000000; - mantissa >>= (-126 - exponent); - exponent = -127; - } - - /* Round off mantissa */ - mantissa = (mantissa + 1) >> 1; - - /* Check if mantissa went over 2.0 */ - if (mantissa & 0x800000) - { - exponent += 1; - mantissa &= 0x7FFFFF; mantissa >>= 1; } + else + { + if (exponent > 127) + { + /* Too large, convert to infinity */ + exponent = 128; + mantissa = 0; + } + else if (exponent < -150) + { + /* Too small, convert to zero */ + exponent = -127; + mantissa = 0; + } + else if (exponent < -126) + { + /* Denormalized */ + mantissa |= 0x1000000; + mantissa >>= (-126 - exponent); + exponent = -127; + } + + /* Round off mantissa */ + mantissa = (mantissa + 1) >> 1; + + /* Check if mantissa went over 2.0 */ + if (mantissa & 0x800000) + { + exponent += 1; + mantissa &= 0x7FFFFF; + mantissa >>= 1; + } + } /* Combine fields */ out.i = mantissa; diff --git a/lib/nanopb/src/pb_encode.c b/lib/nanopb/src/pb_encode.c index 409fec396..de716f7a5 100644 --- a/lib/nanopb/src/pb_encode.c +++ b/lib/nanopb/src/pb_encode.c @@ -82,8 +82,11 @@ bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t cou { if (count > 0 && stream->callback != NULL) { - if (stream->bytes_written + count > stream->max_size) + if (stream->bytes_written + count < stream->bytes_written || + stream->bytes_written + count > stream->max_size) + { PB_RETURN_ERROR(stream, "stream full"); + } #ifdef PB_BUFFER_ONLY if (!buf_write(stream, buf, count)) @@ -262,9 +265,33 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie * submessage fields. */ return safe_read_bool(field->pSize) == false; } + else if (field->descriptor->default_value) + { + /* Proto3 messages do not have default values, but proto2 messages + * can contain optional fields without has_fields (generator option 'proto3'). + * In this case they must always be encoded, to make sure that the + * non-zero default value is overwritten. + */ + return false; + } /* Rest is proto3 singular fields */ - if (PB_LTYPE(type) == PB_LTYPE_BYTES) + if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Simple integer / float fields */ + pb_size_t i; + const char *p = (const char*)field->pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } + else if (PB_LTYPE(type) == PB_LTYPE_BYTES) { const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData; return bytes->size == 0; @@ -302,27 +329,29 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie return true; } } - + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) { - /* Catch-all branch that does byte-per-byte comparison for zero value. - * - * This is for all pointer fields, and for static PB_LTYPE_VARINT, - * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also - * callback fields. These all have integer or pointer value which - * can be compared with 0. - */ - pb_size_t i; - const char *p = (const char*)field->pData; - for (i = 0; i < field->data_size; i++) - { - if (p[i] != 0) - { - return false; - } - } - - return true; + return field->pData == NULL; } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; + return extension == NULL; + } + else if (field->descriptor->field_callback == pb_default_field_callback) + { + pb_callback_t *pCallback = (pb_callback_t*)field->pData; + return pCallback->funcs.encode == NULL; + } + else + { + return field->descriptor->field_callback == NULL; + } + } + + return false; /* Not typically reached, safe default for weird special cases. */ } /* Encode a field with static or pointer allocation, i.e. one whose data @@ -823,7 +852,7 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t } if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) + bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) { PB_RETURN_ERROR(stream, "bytes size exceeded"); } diff --git a/proto b/proto index ebd18145c..d0868e366 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit ebd18145cafb0d09528150b7a5eccd52b581902f +Subproject commit d0868e366bc8f8d9b7ed1d1c5a80cac0de9dc956 diff --git a/src/mesh/mesh.pb.c b/src/mesh/mesh.pb.c index 42b5eb949..ca17e7201 100644 --- a/src/mesh/mesh.pb.c +++ b/src/mesh/mesh.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #include "mesh.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h index 06e4aa3b4..0a1c5eb64 100644 --- a/src/mesh/mesh.pb.h +++ b/src/mesh/mesh.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #ifndef PB_MESH_PB_H_INCLUDED #define PB_MESH_PB_H_INCLUDED @@ -10,10 +10,6 @@ #error Regenerate this file with the current version of nanopb generator. #endif -#ifdef __cplusplus -extern "C" { -#endif - /* Enum definitions */ typedef enum _RouteError { RouteError_NONE = 0, @@ -271,6 +267,10 @@ typedef struct _ToRadio { #define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) +#ifdef __cplusplus +extern "C" { +#endif + /* Initializer values for message structs */ #define Position_init_default {0, 0, 0, 0, 0} #define Data_init_default {_PortNum_MIN, {0, {0}}} @@ -306,12 +306,12 @@ typedef struct _ToRadio { /* Field tags (for use in manual encoding/decoding) */ #define ChannelSettings_tx_power_tag 1 #define ChannelSettings_modem_config_tag 3 +#define ChannelSettings_psk_tag 4 +#define ChannelSettings_name_tag 5 #define ChannelSettings_bandwidth_tag 6 #define ChannelSettings_spread_factor_tag 7 #define ChannelSettings_coding_rate_tag 8 #define ChannelSettings_channel_num_tag 9 -#define ChannelSettings_psk_tag 4 -#define ChannelSettings_name_tag 5 #define Data_portnum_tag 1 #define Data_payload_tag 2 #define DebugString_message_tag 1 @@ -329,10 +329,10 @@ typedef struct _ToRadio { #define MyNodeInfo_node_num_bits_tag 12 #define MyNodeInfo_message_timeout_msec_tag 13 #define MyNodeInfo_min_app_version_tag 14 -#define Position_latitude_i_tag 7 -#define Position_longitude_i_tag 8 #define Position_altitude_tag 3 #define Position_battery_level_tag 4 +#define Position_latitude_i_tag 7 +#define Position_longitude_i_tag 8 #define Position_time_tag 9 #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 #define RadioConfig_UserPreferences_send_owner_interval_tag 2 @@ -349,15 +349,15 @@ typedef struct _ToRadio { #define RadioConfig_UserPreferences_wifi_password_tag 13 #define RadioConfig_UserPreferences_wifi_ap_mode_tag 14 #define RadioConfig_UserPreferences_region_tag 15 +#define RadioConfig_UserPreferences_location_share_tag 32 +#define RadioConfig_UserPreferences_gps_operation_tag 33 +#define RadioConfig_UserPreferences_gps_update_interval_tag 34 +#define RadioConfig_UserPreferences_gps_attempt_time_tag 36 #define RadioConfig_UserPreferences_is_router_tag 37 #define RadioConfig_UserPreferences_is_low_power_tag 38 #define RadioConfig_UserPreferences_fixed_position_tag 39 #define RadioConfig_UserPreferences_factory_reset_tag 100 #define RadioConfig_UserPreferences_debug_log_enabled_tag 101 -#define RadioConfig_UserPreferences_location_share_tag 32 -#define RadioConfig_UserPreferences_gps_operation_tag 33 -#define RadioConfig_UserPreferences_gps_update_interval_tag 34 -#define RadioConfig_UserPreferences_gps_attempt_time_tag 36 #define RadioConfig_UserPreferences_ignore_incoming_tag 103 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 @@ -367,8 +367,8 @@ typedef struct _ToRadio { #define NodeInfo_num_tag 1 #define NodeInfo_user_tag 2 #define NodeInfo_position_tag 3 -#define NodeInfo_snr_tag 7 #define NodeInfo_next_hop_tag 5 +#define NodeInfo_snr_tag 7 #define RadioConfig_preferences_tag 1 #define RadioConfig_channel_settings_tag 2 #define SubPacket_position_tag 1 @@ -377,19 +377,19 @@ typedef struct _ToRadio { #define SubPacket_route_request_tag 6 #define SubPacket_route_reply_tag 7 #define SubPacket_route_error_tag 13 -#define SubPacket_success_id_tag 10 -#define SubPacket_fail_id_tag 11 +#define SubPacket_original_id_tag 2 #define SubPacket_want_response_tag 5 #define SubPacket_dest_tag 9 +#define SubPacket_success_id_tag 10 +#define SubPacket_fail_id_tag 11 #define SubPacket_source_tag 12 -#define SubPacket_original_id_tag 2 -#define MeshPacket_decoded_tag 3 -#define MeshPacket_encrypted_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 +#define MeshPacket_decoded_tag 3 +#define MeshPacket_encrypted_tag 8 #define MeshPacket_id_tag 6 -#define MeshPacket_rx_time_tag 9 #define MeshPacket_rx_snr_tag 7 +#define MeshPacket_rx_time_tag 9 #define MeshPacket_hop_limit_tag 10 #define MeshPacket_want_ack_tag 11 #define DeviceState_radio_tag 1 @@ -397,10 +397,11 @@ typedef struct _ToRadio { #define DeviceState_owner_tag 3 #define DeviceState_node_db_tag 4 #define DeviceState_receive_queue_tag 5 -#define DeviceState_version_tag 8 #define DeviceState_rx_text_message_tag 7 +#define DeviceState_version_tag 8 #define DeviceState_no_save_tag 9 #define DeviceState_did_gps_reset_tag 11 +#define FromRadio_num_tag 1 #define FromRadio_packet_tag 2 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 @@ -408,7 +409,6 @@ typedef struct _ToRadio { #define FromRadio_debug_string_tag 7 #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 -#define FromRadio_num_tag 1 #define ToRadio_packet_tag 1 #define ToRadio_want_config_id_tag 100 #define ToRadio_set_radio_tag 101 @@ -449,7 +449,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \ -X(a, STATIC, ONEOF, ENUM, (payload,route_error,route_error), 13) \ +X(a, STATIC, ONEOF, UENUM, (payload,route_error,route_error), 13) \ X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \ diff --git a/src/mesh/portnums.pb.c b/src/mesh/portnums.pb.c index 0995ab494..4220806db 100644 --- a/src/mesh/portnums.pb.c +++ b/src/mesh/portnums.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #include "portnums.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/portnums.pb.h b/src/mesh/portnums.pb.h index eab09126b..703daa911 100644 --- a/src/mesh/portnums.pb.h +++ b/src/mesh/portnums.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #ifndef PB_PORTNUMS_PB_H_INCLUDED #define PB_PORTNUMS_PB_H_INCLUDED @@ -9,10 +9,6 @@ #error Regenerate this file with the current version of nanopb generator. #endif -#ifdef __cplusplus -extern "C" { -#endif - /* Enum definitions */ typedef enum _PortNum { PortNum_UNKNOWN_APP = 0, @@ -20,6 +16,7 @@ typedef enum _PortNum { PortNum_REMOTE_HARDWARE_APP = 2, PortNum_POSITION_APP = 3, PortNum_NODEINFO_APP = 4, + PortNum_REPLY_APP = 32, PortNum_PRIVATE_APP = 256, PortNum_IP_TUNNEL_APP = 1024 } PortNum; @@ -30,6 +27,10 @@ typedef enum _PortNum { #define _PortNum_ARRAYSIZE ((PortNum)(PortNum_IP_TUNNEL_APP+1)) +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/mesh/remote_hardware.pb.c b/src/mesh/remote_hardware.pb.c index a334db461..77c01e60f 100644 --- a/src/mesh/remote_hardware.pb.c +++ b/src/mesh/remote_hardware.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #include "remote_hardware.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/remote_hardware.pb.h b/src/mesh/remote_hardware.pb.h index f85cd8ff2..853566f0c 100644 --- a/src/mesh/remote_hardware.pb.h +++ b/src/mesh/remote_hardware.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.1 */ +/* Generated by nanopb-0.4.4 */ #ifndef PB_REMOTE_HARDWARE_PB_H_INCLUDED #define PB_REMOTE_HARDWARE_PB_H_INCLUDED @@ -9,10 +9,6 @@ #error Regenerate this file with the current version of nanopb generator. #endif -#ifdef __cplusplus -extern "C" { -#endif - /* Enum definitions */ typedef enum _HardwareMessage_Type { HardwareMessage_Type_UNSET = 0, @@ -37,6 +33,10 @@ typedef struct _HardwareMessage { #define _HardwareMessage_Type_ARRAYSIZE ((HardwareMessage_Type)(HardwareMessage_Type_READ_GPIOS_REPLY+1)) +#ifdef __cplusplus +extern "C" { +#endif + /* Initializer values for message structs */ #define HardwareMessage_init_default {_HardwareMessage_Type_MIN, 0, 0} #define HardwareMessage_init_zero {_HardwareMessage_Type_MIN, 0, 0} diff --git a/src/plugins/ReplyPlugin.cpp b/src/plugins/ReplyPlugin.cpp new file mode 100644 index 000000000..d5c9e727d --- /dev/null +++ b/src/plugins/ReplyPlugin.cpp @@ -0,0 +1,27 @@ +#include "configuration.h" +#include "ReplyPlugin.h" +#include "MeshService.h" +#include "main.h" + +#include + +// Create an a static instance of our plugin - this registers with the plugin system +ReplyPlugin replyPlugin; + +bool ReplyPlugin::handleReceived(const MeshPacket &req) +{ + auto &p = req.decoded.data; + // The incoming message is in p.payload + DEBUG_MSG("Received message from=0x%0x, id=%d, msg=%.*s\n", req.from, req.id, p.payload.size, p.payload.bytes); + + screen->print("Sending reply\n"); + + const char *replyStr = "Message Received"; + auto reply = allocDataPacket(); // Allocate a packet for sending + reply->decoded.data.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply + memcpy(reply->decoded.data.payload.bytes, replyStr, reply->decoded.data.payload.size); + setReplyTo(reply, req); // Set packet params so that this packet is marked as a reply to a previous request + service.sendToMesh(reply); // Queue the reply for sending + + return true; // We handled it +} diff --git a/src/plugins/ReplyPlugin.h b/src/plugins/ReplyPlugin.h new file mode 100644 index 000000000..0d3686b57 --- /dev/null +++ b/src/plugins/ReplyPlugin.h @@ -0,0 +1,23 @@ +#pragma once +#include "SinglePortPlugin.h" + + +/** + * A simple example plugin that just replies with "Message received" to any message it receives. + */ +class ReplyPlugin : public SinglePortPlugin +{ + public: + /** Constructor + * name is for debugging output + */ + ReplyPlugin() : SinglePortPlugin("reply", PortNum_REPLY_APP) {} + + protected: + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +};