Store field descriptor constants in flash on AVR (#464)
diff --git a/pb.h b/pb.h
index 91c1e79..871422d 100644
--- a/pb.h
+++ b/pb.h
@@ -127,6 +127,19 @@
#define PB_UNUSED(x) (void)(x)
#endif
+/* Harvard-architecture processors may need special attributes for storing
+ * field information in program memory. */
+#ifndef PB_PROGMEM
+#ifdef __AVR__
+#include <avr/pgmspace.h>
+#define PB_PROGMEM PROGMEM
+#define PB_PROGMEM_READU32(x) pgm_read_dword(&x)
+#else
+#define PB_PROGMEM
+#define PB_PROGMEM_READU32(x) (x)
+#endif
+#endif
+
/* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use
* #define PB_NO_STATIC_ASSERT to disable it.
@@ -448,7 +461,7 @@
/* Binding of a message field set into a specific structure */
#define PB_BIND(msgname, structname, width) \
- const uint32_t structname ## _field_info[] = \
+ const uint32_t structname ## _field_info[] PB_PROGMEM = \
{ \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
0 \
diff --git a/pb_common.c b/pb_common.c
index 4f7e688..8ff9bd1 100644
--- a/pb_common.c
+++ b/pb_common.c
@@ -15,7 +15,7 @@
if (iter->index >= iter->descriptor->field_count)
return false;
- word0 = iter->descriptor->field_info[iter->field_info_index];
+ 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);
@@ -31,7 +31,7 @@
else if (format == 1)
{
/* 2-word format */
- uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
+ uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6));
@@ -42,9 +42,9 @@
else if (format == 2)
{
/* 4-word format */
- uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
- uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
- uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
+ 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)(iter->tag | ((word1 >> 8) << 6));
@@ -55,10 +55,10 @@
else
{
/* 8-word format */
- uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
- uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
- uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
- uint32_t word4 = iter->descriptor->field_info[iter->field_info_index + 4];
+ 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)(iter->tag | ((word1 >> 8) << 6));
@@ -126,7 +126,7 @@
* - bits 2..7 give the lowest bits of tag number.
* - bits 8..15 give the field type.
*/
- uint32_t prev_descriptor = iter->descriptor->field_info[iter->field_info_index];
+ uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
@@ -159,7 +159,8 @@
const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
bool status;
- if (PB_ATYPE(msg->field_info[0] >> 8) == PB_ATYPE_POINTER)
+ uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
+ if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
@@ -199,7 +200,7 @@
advance_iterator(iter);
/* Do fast check for tag number match */
- fieldinfo = iter->descriptor->field_info[iter->field_info_index];
+ fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
{