Skip to content

Commit

Permalink
Handle nullable attributes in TLV-to-attr-store interactions and Acce…
Browse files Browse the repository at this point in the history
…ssors (#11665)

* Add a way to ask EmberAfAttributeMetadata whether the attribute is nullable.

* Convert ZCL null values to/from TLV null when attributes are read/written.

This implements the following semantics, for attributes we store in
the attribute store (integers, booleans, strings, octet strings):

Writes:

* An attempt to write TLV null for non-nullable attributes leads to an
  error.

* Writing TLV null to a nullable string or octet string sets its length
  to 0xFFFF or 0xFF depending on whether it's a long string or not.

* Writing TLV null to a nullable integer or boolean uses the "NaU" or
  "NaS" ZCL representation to represent it.

* Writing a TLV integer to an integer attribute makes a
  CanRepresentValue check and returns an error if it returns false.
  For now CanRepresentValue only disallows the NaU/NaS value for
  nullable attributes.

Reads:

* When reading a nullable integer or boolean, NaU/NaS is converted to TLV null.

* When reading an integer or boolean all other cases go through a
  CanRepresentValue check (in case the value in the attr store is not
  actually valid) and return error if it returns false.

* When reading a nullable string or octet string, length 0xFFFF/0xFF
  is converted to TLV null.

* When reading a non-nullable string or octet string, length
  0xFFFF/0xFF leads to an error.

* Fix Accessors to handle nullable attributes.

For setters, the new behavior is:

* For non-string attributes when setting an integer or boolean value,
  do a CanRepresentValue check and fail if that fails.  For string
  attributes, ensure that strings with 0xFF or 0xFFFF as length cannot
  be passed in in practice.

* For nullable attributes add a SetNull method.

* For nullable attributes add a Set() method taking a Nullable<T> and
  calling either SetNull or the setter that expects a non-null value.

For getters, the new behavior is:

* When reading a nullable integer or boolean, NaU/NaS is converted to
  a null value stored in the Nullable.

* When reading a non-nullable integer or boolean, return error if
  CanRepresentValue returns false on the value from the attr store.

* When reading a nullable string or octet string, length 0xFFFF/0xFF
  is converted to a null value stored in the Nullable.

* When reading a non-nullable string or octet string, length
  0xFFFF/0xFF leads to an error.

The XML changes are for two problems the new asserts caught: we had
strings that were short-typed, but had sizes that would not fit in a
single byte length.

* Add tests for nullable attributes.

* Fix the Darwin tests by skipping the nullable read for now

* Address review comments
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Jan 25, 2022
1 parent e7aa82e commit 2837681
Show file tree
Hide file tree
Showing 39 changed files with 24,573 additions and 3,433 deletions.
270 changes: 270 additions & 0 deletions examples/all-clusters-app/all-clusters-common/all-clusters-app.zap
Original file line number Diff line number Diff line change
Expand Up @@ -15651,6 +15651,276 @@
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "unsupported",
"code": 255,
"mfgCode": null,
"side": "server",
"included": 0,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_boolean",
"code": 32768,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "false",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_bitmap8",
"code": 32769,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_bitmap16",
"code": 32770,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_bitmap32",
"code": 32771,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_bitmap64",
"code": 32772,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int8u",
"code": 32773,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int16u",
"code": 32774,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int32u",
"code": 32776,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int64u",
"code": 32780,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int8s",
"code": 32781,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int16s",
"code": 32782,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int32s",
"code": 32784,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_int64s",
"code": 32788,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_enum8",
"code": 32789,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_enum16",
"code": 32790,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_octet_string",
"code": 32793,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "nullable_char_string",
"code": 32798,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 0,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "ClusterRevision",
"code": 65533,
Expand Down
Loading

0 comments on commit 2837681

Please sign in to comment.