| # JSON to TLV and TLV to JSON Converter |
| |
| ## Introduction |
| |
| Helper functions for converting TLV-encoded data to Json format and vice versa. |
| |
| ### Supported payloads |
| |
| The library supports |
| |
| - full bi-directional conversion for matter data model payloads |
| - Additional support for generic 32-bit unsigned integer ids using "implicit |
| profile tags": |
| |
| - 8-bit IDs are encoded as `ContextTags`, which matches matter |
| specification for encoding field identifiers |
| - For IDs that are larger, they will be encoded as |
| `Implicit Profile Tags`. The reason for allowing such IDs is to support |
| json formats where keys contain ids typically found in paths, like |
| `{"1234:INT": 10}` meaning `"Attribute 1234 has value 10"`. |
| |
| ### Format details |
| |
| In order for the Json format to represent the TLV format without loss of |
| information, the Json name of each element should contain the TLV element tag |
| and type information. |
| |
| The Json name schema is as follows: |
| |
| ``` |
| { [field_name:]field_id:element_type[-sub_element_type] } |
| ``` |
| |
| Specific rules: |
| |
| - 'element_type' MUST map to the TLV Type as specified in the table below. |
| - For 'element_type' of type "ARRAY", the sub_element_type MUST always be |
| present and be equal to the 'element_type' of the elements in the array. |
| - Array elements MUST have the same 'element_type'. |
| - Array elements MUST have anonymous TLV tags. |
| - 'field_name' is always an optional field and can be provided if the semantic |
| name for the field is available. |
| - In the case of an empty array, 'sub_element_type' should be "?" (unknown |
| element type). |
| - The unknown element type “?” MUST never occur outside of "ARRAY-?". |
| - 'field_id' is equivalent to the Field ID for all cluster payloads (commands, |
| events, attributes), encoded as a decimal number. |
| |
| The table below summarizes all element types and their corresponding encoding in |
| the Json element name: |
| |
| | TLV Type | element_type | JSON Type | |
| | -------------------------------------- | ---------------------- | ------------------------------- | |
| | Unsigned Integer ( < 2^32 ) | UINT | Number | |
| | Unsigned Integer ( >= 2^32 ) | UINT | String | |
| | Signed Integer ( >= -2^31 and < 2^31 ) | INT | Number | |
| | Signed Integer ( < -2^31 or >= 2^31 ) | INT | String | |
| | Boolean | BOOL | Boolean | |
| | Float (positive/negative infinity) | FLOAT | String ("Infinity"/"-Infinity") | |
| | Double (positive/negative infinity) | DOUBLE | String ("Infinity"/"-Infinity") | |
| | Float (not infinity) | FLOAT | Number | |
| | Double (not infinity) | DOUBLE | Number | |
| | Octet String | BYTES | String (Base64 encoded) | |
| | UTF-8 String | STRING | String | |
| | Null Value | NULL | null | |
| | Struct | STRUCT | Dict | |
| | Array | ARRAY-sub_element_type | Array | |
| | Unknown | ? | Empty Array | |
| |
| Note that this is NOT a generalized JSON representation of TLV and does not |
| support arbitrary TLV conversions. The main goal of this Json format is to |
| support data model payloads for events/commands/attributes. Some of the |
| limitations of this format are: |
| |
| - TLV List types are not supported. |
| - TLV Array cannot contain another TLV Array. |
| - The top-level container MUST be an anonymous STRUCT. |
| - Elements of the TLV Structure MUST have Context or Implicit Profile Tags. |
| - Implicit Profile Tag number MUST be larger or equal to 256 and smaller than |
| 2^32 + 1. |
| - TLV Structure element MUST be sorted by tag numbers from low to high, where |
| sorted elements with Context Tags MUST appear first followed by sorted |
| elements with Implicit Profile Tags. |
| |
| ## Format Example |
| |
| The following is an example of a Json string. It represents various TLV |
| elements, arrays, and structures. |
| |
| ``` |
| { // top-level anonymous structure |
| "0:ARRAY-STRUCT" : [ // array of structures |
| { |
| "0:INT" : 8, // Struct.elem0 |
| "1:BOOL" : true // Struct.elem1 |
| } |
| ], |
| "1:STRUCT" : { // structure |
| "0:INT" : 12, // Struct.elem0 |
| "1:BOOL" : false, // Struct.elem1 |
| "2:STRING" : "example" // Struct.elem2 |
| }, |
| "2:INT" : "40000000000", // int as string |
| "isQualified:3:BOOL" : true, // boolean with field_name in the Json name |
| "4:ARRAY-?" : [], // empty array |
| "5:ARRAY-DOUBLE" : [ // array of doubles |
| 1.1, |
| 134.2763, |
| -12345.87, |
| "Infinity", // positive infinity |
| 62534, // positive integer-valued double |
| -62534 // negative integer-valued double |
| ], |
| "6:ARRAY-BYTES" : [ // array of Octet Strings: [{00 01 02 03 04}, {FF}, {4A EF 88}] |
| "AAECAwQ=", // base64( {00 01 02 03 04} ) |
| "/w==", // base64( {FF} ) |
| "Su+I" // base64( {4A EF 88} ) |
| ], |
| "7:BYTES" : "VGVzdCBCeXRlcw==", // base64( "Test Bytes" ) |
| "8:DOUBLE" : 17.9, // 17.9 as double |
| "9:FLOAT" : 17.9, // 17.9 as float |
| "10:FLOAT" : "-Infinity", // Negative infinity float |
| "contact:11:STRUCT" : { // structure example with field_name in the Json name |
| "name:1:STRING" : "John", |
| "age:2:UINT" : 34, |
| "approved:3:BOOL" : true, |
| "kids:4:ARRAY-INT" : [ |
| 5, |
| 9, |
| 10 |
| ] |
| } |
| } |
| ``` |