Add PB_MANY_FIELDS option for supporting fields > 255.
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>
Sat, 30 Jun 2012 16:28:49 +0000 (19:28 +0300)
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>
Sat, 30 Jun 2012 16:28:49 +0000 (19:28 +0300)
Add generator warning if this is necessary.
Fixes issue #14.

docs/reference.rst
generator/nanopb_generator.py
pb.h

index 81251fe..aefc25f 100644 (file)
@@ -15,6 +15,8 @@ __BIG_ENDIAN__                 Set this if your platform stores integers and flo
                                Mixed-endian systems (different layout for ints and floats) are currently not supported.
 NANOPB_INTERNALS               Set this to expose the field encoder functions that are hidden since nanopb-0.1.3.
 PB_MAX_REQUIRED_FIELDS         Maximum number of required fields to check for presence. Default value is 64.
+PB_MANY_FIELDS                 Add support for tag numbers > 255 and fields larger than 255 bytes or 255 array entries.
+                               Increases code size 9 bytes per each field. Compiler error will tell if you need this.
 ============================  ==============================================================================================
 
 pb.h
@@ -77,7 +79,7 @@ Describes a single structure field with memory position in relation to others. T
 :array_size:    Maximum number of entries in an array, if it is an array type.
 :ptr:           Pointer to default value for optional fields, or to submessage description for PB_LTYPE_SUBMESSAGE.
 
-The *uint8_t* datatypes limit the maximum size of a single item to 255 bytes and arrays to 255 items. Compiler will warn "Initializer too large for type" if the limits are exceeded. The types can be changed to larger ones if necessary.
+The *uint8_t* datatypes limit the maximum size of a single item to 255 bytes and arrays to 255 items. Compiler will give error if the values are too large. The types can be changed to larger ones by defining *PB_MANY_FIELDS*.
 
 pb_bytes_array_t
 ----------------
index 730c0aa..405feda 100644 (file)
@@ -251,6 +251,20 @@ class Field:
             result += '\n    &%s_default}' % (self.struct_name + self.name)
         
         return result
+    
+    def needs_32bit_pb_field_t(self):
+        '''Determine if this field needs 32bit pb_field_t structure to compile properly.
+        Returns True, False or a C-expression for assert.'''
+        if self.tag > 255 or self.max_size > 255:
+            return True
+        
+        if self.ltype == 'PB_LTYPE_SUBMESSAGE':
+            if self.htype == 'PB_HTYPE_ARRAY':
+                return 'pb_membersize(%s, %s[0]) > 255' % (self.struct_name, self.name)
+            else:
+                return 'pb_membersize(%s, %s) > 255' % (self.struct_name, self.name)
+        
+        return False
 
 class Message:
     def __init__(self, names, desc):
@@ -412,6 +426,30 @@ def generate_header(dependencies, headername, enums, messages):
         yield '         setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count
         yield '#endif\n'
     
+    worst = False
+    worst_field = ''
+    for msg in messages:
+        for field in msg.fields:
+            status = field.needs_32bit_pb_field_t()
+            if status == True:
+                worst = True
+                worst_field = str(field.struct_name) + '.' + str(field.name)
+            elif status != False:
+                if worst == False:
+                    worst = status
+                elif worst != True:
+                    worst += ' || ' + status
+
+    if worst != False:
+        yield '\n/* Check that field information fits in pb_field_t */\n'
+        yield '#ifndef PB_MANY_FIELDS\n'
+        if worst == True:
+            yield '#error Field descriptor for %s is too large. Define PB_MANY_FIELDS to fix this.\n' % worst_field
+        else:
+            yield 'STATIC_ASSERT(!(%s), YOU_MUST_DEFINE_PB_MANY_FIELDS)\n' % worst
+        yield '#endif\n'
+    
+    # End of header
     yield '\n#endif\n'
 
 def generate_source(headername, enums, messages):
diff --git a/pb.h b/pb.h
index fc74dbd..a81e9ef 100644 (file)
--- a/pb.h
+++ b/pb.h
 #define UNUSED(x) (void)(x)
 #endif
 
+/* Compile-time assertion, used for checking compatible compilation options. */
+#ifndef STATIC_ASSERT
+#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1];
+#endif
+
 /* Number of required fields to keep track of
  * (change here or on compiler command line). */
 #ifndef PB_MAX_REQUIRED_FIELDS
@@ -101,12 +106,22 @@ typedef enum {
  */
 typedef struct _pb_field_t pb_field_t;
 struct _pb_field_t {
+
+#ifndef PB_MANY_FIELDS
     uint8_t tag;
     pb_type_t type;
     uint8_t data_offset; /* Offset of field data, relative to previous field. */
     int8_t size_offset; /* Offset of array size or has-boolean, relative to data */
     uint8_t data_size; /* Data size in bytes for a single item */
     uint8_t array_size; /* Maximum number of entries in array */
+#else
+    uint32_t tag;
+    pb_type_t type;
+    uint8_t data_offset;
+    int8_t size_offset;
+    uint32_t data_size;
+    uint32_t array_size;
+#endif
     
     /* Field definitions for submessage
      * OR default value for all other non-array, non-callback types