aboutsummaryrefslogtreecommitdiff
path: root/docs/concepts.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/concepts.rst')
-rw-r--r--docs/concepts.rst109
1 files changed, 105 insertions, 4 deletions
diff --git a/docs/concepts.rst b/docs/concepts.rst
index 0df5ad6..1f9aec1 100644
--- a/docs/concepts.rst
+++ b/docs/concepts.rst
@@ -148,7 +148,9 @@ Most Protocol Buffers datatypes have directly corresponding C datatypes, such as
1) Strings, bytes and repeated fields of any type map to callback functions by default.
2) If there is a special option *(nanopb).max_size* specified in the .proto file, string maps to null-terminated char array and bytes map to a structure containing a char array and a size field.
-3) If there is a special option *(nanopb).max_count* specified on a repeated field, it maps to an array of whatever type is being repeated. Another field will be created for the actual number of entries stored.
+3) If *(nanopb).fixed_length* is set to *true* and *(nanopb).max_size* is also set, then bytes map to an inline byte array of fixed size.
+4) If there is a special option *(nanopb).max_count* specified on a repeated field, it maps to an array of whatever type is being repeated. Another field will be created for the actual number of entries stored.
+5) If *(nanopb).fixed_count* is set to *true* and *(nanopb).max_count* is also set, the field for the actual number of entries will not by created as the count is always assumed to be max count.
=============================================================================== =======================
field in .proto autogenerated in .h
@@ -160,16 +162,22 @@ repeated string name = 1 [(nanopb).max_size = 40, (nanopb).max_count = 5];
| char name[5][40];
required bytes data = 1 [(nanopb).max_size = 40]; | typedef struct {
| size_t size;
- | uint8_t bytes[40];
+ | pb_byte_t bytes[40];
| } Person_data_t;
| Person_data_t data;
+required bytes data = 1 [(nanopb).max_size = 40, (nanopb).fixed_length = true]; | pb_byte_t data[40];
+repeated int32 data = 1 [(nanopb).max_count = 5, (nanopb).fixed_count true]; | int32_t data[5];
=============================================================================== =======================
The maximum lengths are checked in runtime. If string/bytes/array exceeds the allocated length, *pb_decode* will return false.
-Note: for the *bytes* datatype, the field length checking may not be exact.
+Note: For the *bytes* datatype, the field length checking may not be exact.
The compiler may add some padding to the *pb_bytes_t* structure, and the nanopb runtime doesn't know how much of the structure size is padding. Therefore it uses the whole length of the structure for storing data, which is not very smart but shouldn't cause problems. In practise, this means that if you specify *(nanopb).max_size=5* on a *bytes* field, you may be able to store 6 bytes there. For the *string* field type, the length limit is exact.
+Note: When using the *fixed_count* option, the decoder assumes the repeated elements are
+received sequentially or that repeated elements for a non-packed field will not be interleaved with
+another *fixed_count* non-packed field.
+
Field callbacks
===============
When a field has dynamic length, nanopb cannot statically allocate storage for it. Instead, it allows you to handle the field in whatever way you want, using a callback function.
@@ -255,6 +263,61 @@ generates this field description array for the structure *Person_PhoneNumber*::
PB_LAST_FIELD
};
+Oneof
+=====
+Protocol Buffers supports `oneof`_ sections. Here is an example of ``oneof`` usage::
+
+ message MsgType1 {
+ required int32 value = 1;
+ }
+
+ message MsgType2 {
+ required bool value = 1;
+ }
+
+ message MsgType3 {
+ required int32 value1 = 1;
+ required int32 value2 = 2;
+ }
+
+ message MyMessage {
+ required uint32 uid = 1;
+ required uint32 pid = 2;
+ required uint32 utime = 3;
+
+ oneof payload {
+ MsgType1 msg1 = 4;
+ MsgType2 msg2 = 5;
+ MsgType3 msg3 = 6;
+ }
+ }
+
+Nanopb will generate ``payload`` as a C union and add an additional field ``which_payload``::
+
+ typedef struct _MyMessage {
+ uint32_t uid;
+ uint32_t pid;
+ uint32_t utime;
+ pb_size_t which_payload;
+ union {
+ MsgType1 msg1;
+ MsgType2 msg2;
+ MsgType3 msg3;
+ } payload;
+ /* @@protoc_insertion_point(struct:MyMessage) */
+ } MyMessage;
+
+``which_payload`` indicates which of the ``oneof`` fields is actually set.
+The user is expected to set the filed manually using the correct field tag::
+
+ MyMessage msg = MyMessage_init_zero;
+ msg.payload.msg2.value = true;
+ msg.which_payload = MyMessage_msg2_tag;
+
+Notice that neither ``which_payload`` field nor the unused fileds in ``payload``
+will consume any space in the resulting encoded message.
+
+.. _`oneof`: https://developers.google.com/protocol-buffers/docs/reference/proto2-spec#oneof_and_oneof_field
Extension fields
================
@@ -299,6 +362,44 @@ An example of this is available in *tests/test_encode_extensions.c* and
.. _`extension fields`: https://developers.google.com/protocol-buffers/docs/proto#extensions
+Default values
+==============
+Protobuf has two syntax variants, proto2 and proto3. Of these proto2 has user
+definable default values that can be given in .proto file::
+
+ message MyMessage {
+ optional bytes foo = 1 [default = "ABC\x01\x02\x03"];
+ optional string bar = 2 [default = "åäö"];
+ }
+
+Nanopb will generate both static and runtime initialization for the default
+values. In `myproto.pb.h` there will be a `#define MyMessage_init_default` that
+can be used to initialize whole message into default values::
+
+ MyMessage msg = MyMessage_init_default;
+
+In addition to this, `pb_decode()` will initialize message fields to defaults
+at runtime. If this is not desired, `pb_decode_noinit()` can be used instead.
+
+Message framing
+===============
+Protocol Buffers does not specify a method of framing the messages for transmission.
+This is something that must be provided by the library user, as there is no one-size-fits-all
+solution. Typical needs for a framing format are to:
+
+1. Encode the message length.
+2. Encode the message type.
+3. Perform any synchronization and error checking that may be needed depending on application.
+
+For example UDP packets already fullfill all the requirements, and TCP streams typically only
+need a way to identify the message length and type. Lower level interfaces such as serial ports
+may need a more robust frame format, such as HDLC (high-level data link control).
+
+Nanopb provides a few helpers to facilitate implementing framing formats:
+
+1. Functions *pb_encode_delimited* and *pb_decode_delimited* prefix the message data with a varint-encoded length.
+2. Union messages and oneofs are supported in order to implement top-level container messages.
+3. Message IDs can be specified using the *(nanopb_msgopt).msgid* option and can then be accessed from the header.
Return values and error handling
================================
@@ -312,5 +413,5 @@ The error messages help in guessing what is the underlying cause of the error. T
3) IO errors in your own stream callbacks.
4) Errors that happen in your callback functions.
5) Exceeding the max_size or bytes_left of a stream.
-6) Exceeding the max_size of a string or array field
+6) Exceeding the max_size/max_count of a string or array field
7) Invalid protocol buffers binary message.