diff --git a/docs/code-prettify/run_prettify.js b/docs/code-prettify/run_prettify.js
index 5cf0202be..ba4ac4dfe 100644
--- a/docs/code-prettify/run_prettify.js
+++ b/docs/code-prettify/run_prettify.js
@@ -489,6 +489,7 @@ var IN_GLOBAL_SCOPE = false;
"set," +
"severity," +
"signal," +
+ "signed," +
"size," +
"sizeof," +
"stack," +
@@ -504,6 +505,7 @@ var IN_GLOBAL_SCOPE = false;
"topology," +
"type," +
"unmatched," +
+ "unsigned," +
"update," +
"warning," +
"with," +
diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html
index 5a8cc52b5..41a750a97 100644
--- a/docs/fpp-spec.html
+++ b/docs/fpp-spec.html
@@ -1301,6 +1301,7 @@
3.1. Reserved Words
set
severity
signal
+signed
size
sizeof
stack
@@ -1316,6 +1317,7 @@ 3.1. Reserved Words
true
type
unmatched
+unsigned
update
warning
with
@@ -3697,8 +3699,12 @@ 5.13.1. Syntax
struct-type-member-sequence is an element sequence
in which the elements are struct type members, and the terminating
punctuation is a comma.
-A struct type member has the following syntax:
+A struct type member has one of the following two forms:
+
+
+-
+
A typed member:
+
+-
+
A bit field member:
+
+
+
+
5.13.2. Semantics
@@ -3720,7 +3740,7 @@ 5.13.2. Semantics
identifier appearing in the struct type member sequence must be distinct.
-
For each member m,
+
For each typed member m,
@@ -3748,6 +3768,59 @@ 5.13.2. Semantics
+
For each bit field member m,
+
+
+
+-
+
The keyword signed or unsigned specifies the signedness of m.
+
+-
+
The expression following the keyword specifies the bit width
+\$w_m\$ of m.
+The expression must have a
+numeric type, and it must
+evaluate to a value \$w_m\$ after conversion to
+Integer, with
+\$1 <= w_m <= 64\$.
+
+-
+
The type \$T_m\$ of m is the
+primitive integer type
+with the specified signedness and with the smallest width
+greater than or equal to \$w_m\$.
+For example, the type of a member unsigned 4 is U8, and
+the type of a member signed 12 is I16.
+This type governs the use of the member in expressions and its
+representation in generated code.
+
+-
+
The value stored in m must be representable in \$w_m\$ bits:
+in the range \$[0, 2^(w_m)-1]\$ if m is unsigned, and in the range
+\$[-2^(w_m-1), 2^(w_m-1)-1]\$ if m is signed.
+In particular, if the default value of the struct type specifies a
+value for m, then the value must lie in this range.
+
+-
+
A bit field member represents a single value; it may not have a
+size expression [ e ].
+
+-
+
The optional format specifier behaves as it does for a typed
+member.
+
+
+
+
+
The bit width affects only the serialized form of the struct type,
+not the in-memory representation.
+Each maximal sequence of consecutive bit field members in the struct
+type member sequence forms a bit field group.
+The members of a bit field group are packed into a sequence of bytes
+as described in the section on
+serialized sizes.
+
+
The expression following the keyword default is optional.
If present, it specifies the default value
associated with the type.
@@ -3792,7 +3865,20 @@
5.13.3. Examples
# The default value of D stores 1 into each of the 3 elements of x
struct D {
x: [3] U32
-} default { x = 1 }
+} default { x = 1 }
+
+# Defines a struct type E with two bit field members and one
+# typed member.
+# a and b form a bit field group of 12 bits, which is packed
+# into 16 serialized bits (12 bits of data and 4 zero pad bits).
+# The type of a is U8; the type of b is I16.
+# The serialized size of E is 6 bytes: 2 bytes for the bit field
+# group and 4 bytes for x.
+struct E {
+ a: unsigned 3
+ b: signed 9
+ x: U32
+}
@@ -11554,8 +11640,11 @@ 17.19. Serialized Sizes
If T is a
struct type, then s
-the sum of the serialized sizes of the members of T.
-For each member m with type \$T_m\$:
+the sum of the serialized sizes of the members of T
+and of the
+bit field groups of T,
+in declaration order.
+For each member m with type \$T_m\$ that is not a bit field member:
-
@@ -11569,6 +11658,34 @@
17.19. Serialized Sizes
+Each bit field group G of a struct type is serialized as a unit,
+as follows:
+
+
+-
+
Let w be the sum of the bit widths of the members of G.
+The serialized size of G is w divided by 8, rounded up to the
+nearest integer, in bytes.
+
+-
+
The members of G are packed in declaration order into
+the serialized bytes, from the most significant bit of the first
+byte towards the least significant bit of the last byte,
+with no intervening bits.
+Each member occupies exactly its bit width, using the standard
+binary representation of an unsigned integer or the two’s complement
+representation of a signed integer.
+
+-
+
If w is not a multiple of 8, then the low-order bits of the
+last byte that are not occupied by any member are pad bits.
+Pad bits are zero in the serialized form and are ignored during
+deserialization.
+
+
+
+
+
If T is an
alias type, then s is the serialized size of the
underlying type of T.
@@ -13309,7 +13426,7 @@
diff --git a/docs/spec/Definitions/Struct-Definitions.adoc b/docs/spec/Definitions/Struct-Definitions.adoc
index fbd9d3ce5..2e67ed852 100644
--- a/docs/spec/Definitions/Struct-Definitions.adoc
+++ b/docs/spec/Definitions/Struct-Definitions.adoc
@@ -15,8 +15,10 @@ _[_ `default` <> _]_
_struct-type-member-sequence_ is an <>
in which the elements are struct type members, and the terminating
punctuation is a comma.
-A *struct type member* has the following syntax:
+A *struct type member* has one of the following two forms:
+. A *typed member*:
++
<> `:`
_[_
`[` <> `]`
@@ -26,6 +28,15 @@ _[_
`format` <>
_]_
+. A *bit field member*:
++
+<> `:`
+( `signed` | `unsigned` )
+<>
+_[_
+`format` <>
+_]_
+
==== Semantics
The identifier is the name _N_ of the type.
@@ -34,7 +45,7 @@ The definition associates the name _N_ with a
of the specified type. Each
identifier appearing in the struct type member sequence must be distinct.
-For each member _m_,
+For each typed member _m_,
* The type name specifies the type stem:[T_m] of the member.
@@ -54,6 +65,47 @@ There is one argument to the format string, which is the member value.
If the size of the member is greater than one, then the
translator applies the format to each element.
+For each bit field member _m_,
+
+* The keyword `signed` or `unsigned` specifies the *signedness* of _m_.
+
+* The expression following the keyword specifies the *bit width*
+stem:[w_m] of _m_.
+The expression must have a
+<>, and it must
+evaluate to a value stem:[w_m] after conversion to
+<>, with
+stem:[1 <= w_m <= 64].
+
+* The type stem:[T_m] of _m_ is the
+<>
+with the specified signedness and with the smallest width
+greater than or equal to stem:[w_m].
+For example, the type of a member `unsigned 4` is `U8`, and
+the type of a member `signed 12` is `I16`.
+This type governs the use of the member in expressions and its
+representation in generated code.
+
+* The value stored in _m_ must be representable in stem:[w_m] bits:
+in the range stem:[[0, 2^(w_m)-1\]] if _m_ is unsigned, and in the range
+stem:[[-2^(w_m-1), 2^(w_m-1)-1\]] if _m_ is signed.
+In particular, if the default value of the struct type specifies a
+value for _m_, then the value must lie in this range.
+
+* A bit field member represents a single value; it may not have a
+size expression `[` _e_ `]`.
+
+* The optional format specifier behaves as it does for a typed
+member.
+
+The bit width affects only the serialized form of the struct type,
+not the in-memory representation.
+Each maximal sequence of consecutive bit field members in the struct
+type member sequence forms a *bit field group*.
+The members of a bit field group are packed into a sequence of bytes
+as described in the section on
+<>.
+
The expression following the keyword `default` is optional.
If present, it specifies the <>
associated with the type.
@@ -97,4 +149,17 @@ struct C {
struct D {
x: [3] U32
} default { x = 1 }
+
+# Defines a struct type E with two bit field members and one
+# typed member.
+# a and b form a bit field group of 12 bits, which is packed
+# into 16 serialized bits (12 bits of data and 4 zero pad bits).
+# The type of a is U8; the type of b is I16.
+# The serialized size of E is 6 bytes: 2 bytes for the bit field
+# group and 4 bytes for x.
+struct E {
+ a: unsigned 3
+ b: signed 9
+ x: U32
+}
----
diff --git a/docs/spec/Lexical-Elements.adoc b/docs/spec/Lexical-Elements.adoc
index b5aeb168d..6cf4cf596 100644
--- a/docs/spec/Lexical-Elements.adoc
+++ b/docs/spec/Lexical-Elements.adoc
@@ -125,6 +125,7 @@ serial
set
severity
signal
+signed
size
sizeof
stack
@@ -140,6 +141,7 @@ topology
true
type
unmatched
+unsigned
update
warning
with
diff --git a/docs/spec/Types.adoc b/docs/spec/Types.adoc
index 573143b72..56e276259 100644
--- a/docs/spec/Types.adoc
+++ b/docs/spec/Types.adoc
@@ -297,14 +297,37 @@ representation type of _T_.
* If _T_ is a
<>, then _s_
-the sum of the serialized sizes of the members of _T_.
-For each member _m_ with type stem:[T_m]:
+the sum of the serialized sizes of the members of _T_
+and of the
+<> of _T_,
+in declaration order.
+For each member _m_ with type stem:[T_m] that is not a bit field member:
** If _m_ has size _n_, then the serialized size of
_m_ is _n_ times the serialized size of stem:[T_m].
** Otherwise the serialized size of _m_ is the serialized size of stem:[T_m].
+* Each bit field group _G_ of a struct type is serialized as a unit,
+as follows:
+
+** Let _w_ be the sum of the bit widths of the members of _G_.
+The serialized size of _G_ is _w_ divided by 8, rounded up to the
+nearest integer, in bytes.
+
+** The members of _G_ are packed in declaration order into
+the serialized bytes, from the most significant bit of the first
+byte towards the least significant bit of the last byte,
+with no intervening bits.
+Each member occupies exactly its bit width, using the standard
+binary representation of an unsigned integer or the two's complement
+representation of a signed integer.
+
+** If _w_ is not a multiple of 8, then the low-order bits of the
+last byte that are not occupied by any member are *pad bits*.
+Pad bits are zero in the serialized form and are ignored during
+deserialization.
+
* If _T_ is an
<>, then _s_ is the serialized size of the
<> of _T_.
diff --git a/editors/emacs/fpp-mode.el b/editors/emacs/fpp-mode.el
index 372635f1f..433e7faf1 100644
--- a/editors/emacs/fpp-mode.el
+++ b/editors/emacs/fpp-mode.el
@@ -50,9 +50,9 @@
"locate" "low" "match" "on" "opcode" "orange"
"output" "param" "passive" "phase" "priority"
"queue" "queued" "raw" "recv" "red"
- "ref" "reg" "resp" "save" "signal" "serial" "set" "severity"
+ "ref" "reg" "resp" "save" "signal" "signed" "serial" "set" "severity"
"size" "sizeof" "stack" "sync" "telemetry" "text" "throttle"
- "time" "true" "unmatched" "update" "enter" "warning" "with"
+ "time" "true" "unmatched" "unsigned" "update" "enter" "warning" "with"
"yellow")
"All non-definition keywords for FPP.")
diff --git a/editors/vim/fpp.vim b/editors/vim/fpp.vim
index 5b7f24e98..36a7f1c79 100644
--- a/editors/vim/fpp.vim
+++ b/editors/vim/fpp.vim
@@ -93,6 +93,7 @@ syn keyword fppKeyword serial
syn keyword fppKeyword set
syn keyword fppKeyword severity
syn keyword fppKeyword signal
+syn keyword fppKeyword signed
syn keyword fppKeyword size
syn keyword fppKeyword sizeof
syn keyword fppKeyword stack
@@ -108,6 +109,7 @@ syn keyword fppKeyword topology
syn keyword fppKeyword true
syn keyword fppKeyword type
syn keyword fppKeyword unmatched
+syn keyword fppKeyword unsigned
syn keyword fppKeyword update
syn keyword fppKeyword warning
syn keyword fppKeyword with