Matter update Interaction Model revision (#24441)

This commit is contained in:
s-hadinger
2026-02-11 21:12:47 +01:00
committed by GitHub
parent 24dfe19bb9
commit d62616a9f6
7 changed files with 399 additions and 22 deletions
@@ -0,0 +1,366 @@
# Matter 1.4.1 Spec vs Tasmota Implementation — Gap Analysis & Change Spec
## 1. Executive Summary
This document compares the Matter 1.4.1 Core Specification (March 2025) against the current Tasmota Berry implementation across the message layer, commissioning (PASE/CASE), and Interaction Model. The implementation is solid and functionally correct for a resource-constrained device. The gaps identified are primarily around **session parameter negotiation** (new mandatory fields in 1.4), **InteractionModelRevision** being outdated, and a few minor protocol conformance items. No architectural changes are recommended — the current layered design is clean and appropriate for the platform.
---
## 2. Layer-by-Layer Analysis
### 2.1 Message Layer (`Matter_Message.be`)
#### What matches the spec well:
- Message header encoding/decoding (flags, DSIZ, session ID, message counter, source/dest node IDs) — correct per §4.4
- Security flags (P, C, MX, SessionType) — correctly parsed
- Protocol header (exchange flags I/A/R/SX/V, opcode, exchange ID, protocol ID, vendor ID, ack counter) — correct per §4.4
- Nonce construction for encryption/decryption (SecurityFlags || MessageCounter || SourceNodeID, 13 bytes) — correct per §4.7
- AES-128-CCM encryption/decryption with 16-byte MIC — correct per §4.7
- Privacy flag handling with AES-CTR decryption — present (§4.8)
- Message version check (bits 3-7 of flags must be 0x00 for Matter 1.0) — correct
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| M1 | Privacy encryption nonce uses `session_id` in big-endian but spec says little-endian for the 2-byte session ID in the privacy nonce | §4.8 | Low | The privacy nonce is `SessionID(2) || MIC[0..10]`. Current code uses `self.local_session_id` with `-2` (big-endian). Should verify byte order. |
| M2 | Message Extensions (MX flag) are skipped but never generated | §4.4 | None | Correct behavior for a device that doesn't use MX. Parsing correctly skips them. |
| M3 | Secured Extensions (SX flag) are skipped but never generated | §4.4 | None | Same as above, correct. |
**Verdict: Message layer is spec-compliant. No changes needed.**
---
### 2.2 Message Handler (`Matter_MessageHandler.be`)
#### What matches the spec well:
- Dispatches unencrypted (session_id=0, sesstype=0) to commissioning — correct
- Dispatches encrypted messages by looking up session via `local_session_id` — correct
- Protocol ID routing: 0x0000 → Secure Channel, 0x0001 → Interaction Model — correct per §4.5
- Duplicate message detection using counter validation — correct per §4.6
- MRP standalone acknowledgement handling (opcode 0x10) — correct per §4.9
- Control message (sec_p flag) routing — present
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| MH1 | BDX (protocol 0x0002) and UDC (protocol 0x0003) are commented out | §4.5 | None | Intentional — BDX is for OTA file transfer, UDC is for commissioner devices. Neither is needed for a basic Matter device. |
| MH2 | No MCSP (Message Counter Synchronization Protocol, opcode 0x00/0x01) handling | §4.6 | Low | MCSP is needed for group messaging counter sync. Since Tasmota doesn't support group messaging, this is acceptable. |
**Verdict: Message handler is correct. No changes needed.**
---
### 2.3 Commissioning — PASE (`Matter_Commissioning_Context.be`, `Matter_Commissioning_Data.be`)
#### What matches the spec well:
- PBKDFParamRequest parsing (tag 1=initiatorRandom, 2=initiatorSessionId, 3=passcodeId, 4=hasPBKDFParameters, 5=sessionParams) — correct per §4.11
- PBKDFParamResponse generation (tag 1=initiatorRandom, 2=responderRandom, 3=responderSessionId, 4=pbkdf_parameters) — correct per §4.11
- SPAKE2+ computation with Matter variant context prefix "CHIP PAKE V1 Commissioning" — correct
- Pake1/Pake2/Pake3 message flow — correct per §4.11
- Session key derivation: `HKDF(Ke, [], "SessionKeys", 48)` → I2R || R2I || AC — correct per §4.11
- StatusReport for PakeFinished — correct
- PBKDF iterations (1000) within spec range (1000-100000) — correct per §3.1
- Salt generation (16 bytes random) within spec range (16-32) — correct per §3.4
- Passcode validation (invalid passcodes list) — correct per §5.1
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| P1 | **Session parameter struct in PBKDFParamResponse only sends SII/SAI (tags 1,2), missing mandatory fields: DATA_MODEL_REVISION (tag 4), INTERACTION_MODEL_REVISION (tag 5), SPECIFICATION_VERSION (tag 6), MAX_PATHS_PER_INVOKE (tag 7)** | §4.10 | **HIGH** | Matter 1.4 made these fields mandatory in the session-parameter-struct. The current implementation only sends SLEEPY_IDLE_INTERVAL and SLEEPY_ACTIVE_INTERVAL. Modern controllers may expect these fields. |
| P2 | PBKDFParamRequest parsing doesn't extract new session parameter fields from initiator | §4.10 | Medium | Should parse and potentially use DATA_MODEL_REVISION, SPECIFICATION_VERSION etc. from the initiator for compatibility negotiation. |
| P3 | SESSION_ACTIVE_THRESHOLD (tag 3, uint16) not sent in session params | §4.10 | Medium | Default is 4000ms per spec. Should be included. |
---
### 2.4 Commissioning — CASE (`Matter_Commissioning_Context.be`)
#### What matches the spec well:
- Sigma1 parsing (initiatorRandom, initiatorSessionId, destinationId, initiatorEphPubKey, resumptionID, initiatorResumeMIC) — correct per §4.12
- Destination Identifier computation: `HMAC(IPK, initiatorRandom || rootPublicKey || fabricId || nodeId)` — correct per §4.12
- Sigma2 generation with TBSData2 and TBEData2 — correct per §4.12
- S2K derivation: `HKDF(SharedSecret, IPK||ResponderRandom||ResponderEphPubKey||TranscriptHash, "Sigma2", 16)` — correct
- S3K derivation: `HKDF(SharedSecret, IPK||TranscriptHash, "Sigma3", 16)` — correct
- TBEData2/3 nonces: "NCASE_Sigma2N" / "NCASE_Sigma3N" — correct per §4.12
- Session key derivation: `HKDF(SharedSecret, IPK||TranscriptHash, "SessionKeys", 48)` — correct
- CASE Resumption flow (S1RK, S2RK, Resume1MIC, Resume2MIC) — correct per §4.12
- Resumption session keys: `HKDF(SharedSecret, initiatorRandom||ResumptionID, "SessionResumptionKeys", 48)` — correct
- Resume nonces: "NCASE_SigmaS1" / "NCASE_SigmaS2" — correct
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| C1 | **Sigma2 and Sigma2Resume don't include responderSessionParams with mandatory fields** | §4.10, §4.12 | **HIGH** | Same as P1 — the session-parameter-struct with DATA_MODEL_REVISION, INTERACTION_MODEL_REVISION, SPECIFICATION_VERSION, MAX_PATHS_PER_INVOKE must be sent. |
| C2 | Sigma3 validation doesn't verify NOC chain back to TrustedRCAC | §4.12 | Medium | There's a TODO comment in the code. The NOC signature is verified, but the full certificate chain validation (NOC → ICAC → RCAC) is not performed. This is a known shortcut. |
| C3 | Sigma3 doesn't verify that the Fabric ID in the initiator's NOC matches the session's fabric | §4.12 | Medium | The code extracts `initiatorFabricId` but doesn't compare it against the session's fabric ID. |
| C4 | SUPPORTED_TRANSPORTS (tag 8) not sent in session params | §4.10 | Low | Optional but useful for indicating UDP-only support. |
---
### 2.5 Commissioning — mDNS Discovery (`Matter_z_Commissioning.be`)
#### What matches the spec well:
- Commissionable discovery: `_matterc._udp` service type — correct per §4.3.1
- Random 16-char hex instance name — correct per §4.3.1
- TXT records: D (discriminator), VP (vendor+product), CM (commissioning mode), T (TCP support) — correct
- Subtypes: `_L<discriminator>`, `_S<upper4bits>`, `_V<vendorID>`, `_CM1` — correct per §4.3.1
- Operational discovery: `_matter._tcp` with `<CompressedFabricID>-<NodeID>` instance — correct per §4.3.2
- SII=500, SAI=300 defaults — correct per §4.10
- Port 5540 — correct per §2.4
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| D1 | Operational discovery TXT records don't include SII, SAI, SAT, T, ICD keys | §4.3.2 | Low | For an always-on WiFi device, these are optional but recommended. The `T` key (TCP support bitmap) should be 0. |
| D2 | No `_T<devicetype>` subtype in commissionable discovery | §4.3.1 | Low | Optional but useful for filtering. |
| D3 | `DN` (device name) TXT record not included in commissionable discovery | §4.3.1 | Low | Optional. |
---
### 2.6 Interaction Model (`Matter_IM.be`, `Matter_IM_Message.be`, `Matter_IM_Data.be`)
#### What matches the spec well:
- All IM opcodes handled: StatusResponse(0x01), ReadRequest(0x02), SubscribeRequest(0x03), SubscribeResponse(0x04), ReportData(0x05), WriteRequest(0x06), WriteResponse(0x07), InvokeRequest(0x08), InvokeResponse(0x09), TimedRequest(0x0A) — correct per §8.4
- ReadRequestMessage structure (AttributeRequests, EventRequests, EventFilters, FabricFiltered, DataVersionFilters) — correct per §8.5
- ReportDataMessage structure (SubscriptionId, AttributeReports, EventReports, MoreChunkedMessages, SuppressResponse) — correct per §8.5
- WriteRequestMessage/WriteResponseMessage — correct per §8.5
- InvokeRequestMessage/InvokeResponseMessage — correct per §8.5
- SubscribeRequestMessage/SubscribeResponseMessage — correct per §8.5
- AttributePathIB encoding (endpoint/cluster/attribute/ListIndex) — correct per §8.2
- Chunked message handling with MAX_MESSAGE=1150 (within 1280 MTU minus headers) — correct per §4.4.4
- Subscription management with min/max intervals — correct
- Solo (fast-path) optimization for single attribute reads and single invoke requests — good optimization
- Event support with EventGenerator and event filtering — correct
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| IM1 | ~~**InteractionModelRevision = 11 (Matter 1.2)**. Matter 1.4 requires revision 12.~~ ✅ FIXED | §8.4 | ~~**HIGH**~~ | Updated to 12 in all outgoing paths (TLV-based and raw-encoded). Also fixed incoming solo parser to accept any revision. |
| IM2 | TimedRequest handling sends SUCCESS but doesn't enforce timed interaction semantics | §8.4 | Medium | The `process_timed_request` method sends a success status but doesn't track the timed window. Subsequent Write/Invoke within the timeout should check `TimedRequest` flag. Currently `timed_request` field in WriteRequest/InvokeRequest is parsed but not validated. |
| IM3 | DataVersionFilters in ReadRequest are parsed but not used for filtering | §8.5 | Low | The spec says if a DataVersionFilter matches the current cluster data version, the cluster's attributes should be omitted from the response. This optimization is not implemented. |
| IM4 | No `PATHS_EXHAUSTED` (0xC8) status code handling when too many paths are requested | §8.3 | Low | The spec limits to 9 attribute paths and 10 event paths per request. No enforcement. |
| IM5 | Subscription max_interval is hardcoded to 60 seconds regardless of requested ceiling | IM_Subscription.be | Low | `max_interval = 60` is forced. The spec allows up to 3600s. This is a deliberate choice for responsiveness but limits battery-powered controller scenarios. |
---
### 2.7 Cluster Revisions and Data Model
#### What matches:
- DataModelRevision = 18 (Matter 1.3+, compatible with 1.4.1) — correct
- Basic Information cluster revision = 3 — correct for Matter 1.4.1
- Descriptor cluster revision = 2 — correct
- Global attributes (0xFFF8-0xFFFD) handled — correct per §7.4
#### Gaps:
| # | Gap | Spec Reference | Severity | Notes |
|---|-----|---------------|----------|-------|
| CL1 | SpecificationVersion attribute (0x0015) in Basic Information cluster — need to verify it's set correctly | §11.1 | Medium | Should be `0x01040100` for Matter 1.4.1. |
| CL2 | MaxPathsPerInvoke attribute (0x0016) in Basic Information cluster — need to verify | §11.1 | Low | Should be 1 (single invoke path). |
---
## 3. Architecture Assessment
The current architecture is well-suited for the platform:
```
Matter_MessageHandler (dispatch)
├── Matter_Commisioning_Context (PASE/CASE)
├── Matter_IM (Interaction Model)
│ ├── Matter_IM_Message (response queue)
│ ├── Matter_IM_Subscription (subscription shop)
│ └── PathGenerator / EventGenerator (lazy evaluation)
└── Matter_Control_Message (MCSP)
```
**No architectural changes recommended.** The separation of concerns is clean:
- Message framing/crypto is isolated in `Matter_Frame`
- Session management is separate from message handling
- IM has a clean send queue with proper exchange tracking
- The "solo" fast-path optimization for single reads/invokes is a smart performance choice
- Lazy (pull) evaluation of attributes during ReportData generation is memory-efficient
---
## 4. Recommended Changes — Detailed Specification
### Change 1: Add Mandatory Session Parameters (HIGH Priority)
**Files affected:** `Matter_Commissioning_Data.be`, `Matter_Commissioning_Context.be`
**Rationale:** Matter 1.4 made several fields mandatory in the `session-parameter-struct` (tag 5 in PBKDFParamResponse, Sigma2, Sigma2Resume). Modern controllers (Apple Home, Google Home, Samsung SmartThings) may reject sessions that don't include these fields.
**Spec reference:** §4.10 Session Parameter TLV
**Current behavior:** Only `SESSION_IDLE_INTERVAL` (tag 1) and `SESSION_ACTIVE_INTERVAL` (tag 2) are conditionally sent.
**Required behavior:** The responder session params struct must include:
```
session-parameter-struct => STRUCTURE [tag-order] {
SESSION_IDLE_INTERVAL [1, optional]: UNSIGNED INTEGER [32-bits], // 500 (ms)
SESSION_ACTIVE_INTERVAL [2, optional]: UNSIGNED INTEGER [32-bits], // 300 (ms)
SESSION_ACTIVE_THRESHOLD [3, optional]: UNSIGNED INTEGER [16-bits], // 4000 (ms)
DATA_MODEL_REVISION [4]: UNSIGNED INTEGER [16-bits], // 18
INTERACTION_MODEL_REVISION [5]: UNSIGNED INTEGER [16-bits], // 12
SPECIFICATION_VERSION [6]: UNSIGNED INTEGER [32-bits], // 0x01040100
MAX_PATHS_PER_INVOKE [7]: UNSIGNED INTEGER [16-bits], // 1
}
```
**Implementation plan:**
1. In `Matter_PBKDFParamResponse.tlv2raw()`: Always generate the session params struct (tag 5) with all mandatory fields.
2. In `Matter_Sigma2.tlv2raw()`: Always generate the session params struct (tag 5) with all mandatory fields.
3. In `Matter_Sigma2Resume.tlv2raw()`: Always generate the session params struct (tag 4) with all mandatory fields.
4. Define constants in a central location (e.g., `matter` module or a static in the commissioning class):
- `DATA_MODEL_REVISION = 18`
- `INTERACTION_MODEL_REVISION = 12`
- `SPECIFICATION_VERSION = 0x01040100` (1.4.1.0)
- `MAX_PATHS_PER_INVOKE = 1`
**Example code change for `Matter_PBKDFParamResponse.tlv2raw()`:**
```berry
def tlv2raw(b)
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(1, TLV.B1, self.initiatorRandom)
s.add_TLV(2, TLV.B1, self.responderRandom)
s.add_TLV(3, TLV.U2, self.responderSessionId)
var s_pbkdf = s.add_struct(4)
s_pbkdf.add_TLV(1, TLV.U4, self.pbkdf_parameters_iterations)
s_pbkdf.add_TLV(2, TLV.B1, self.pbkdf_parameters_salt)
# Always include session params with mandatory fields
var s2 = s.add_struct(5)
s2.add_TLV(1, TLV.U4, 500) # SESSION_IDLE_INTERVAL
s2.add_TLV(2, TLV.U4, 300) # SESSION_ACTIVE_INTERVAL
s2.add_TLV(3, TLV.U2, 4000) # SESSION_ACTIVE_THRESHOLD
s2.add_TLV(4, TLV.U2, 18) # DATA_MODEL_REVISION
s2.add_TLV(5, TLV.U2, 12) # INTERACTION_MODEL_REVISION
s2.add_TLV(6, TLV.U4, 0x01040100) # SPECIFICATION_VERSION (1.4.1.0)
s2.add_TLV(7, TLV.U2, 1) # MAX_PATHS_PER_INVOKE
return s.tlv2raw(b)
end
```
---
### Change 2: Update InteractionModelRevision to 12 ~~(HIGH Priority)~~ ✅ DONE
**Files changed:** `Matter_IM_Data.be`, `Matter_IM_Message.be`, `Matter_IM.be`
**What was done:**
- `Matter_IM_Data.be`: `InteractionModelRevision` set to `12` (was `11`). Also fixed `InvokeRequestMessage_solo.from_raw()` to accept any IM revision value from incoming messages instead of hardcoding `0x24FF0118`.
- `Matter_IM_Message.be`: Raw-encoded IM revision in `ReportData_Pull.send_im()` changed from `0x01` to `12` (0x0C).
- `Matter_IM.be`: Three raw-encoded suffixes in solo fast-paths changed from `0x1824FF01` to `0x1824FF0C` — covering `process_read_request_solo` (two paths: success and error) and `process_invoke_request_solo`.
---
### Change 3: Timed Interaction Enforcement (MEDIUM Priority)
**Files affected:** `Matter_IM.be`
**Rationale:** The current implementation accepts TimedRequest and returns SUCCESS, but doesn't track the timed window. A subsequent Write or Invoke with `timed_request=true` should only succeed if a TimedRequest was received within the timeout window on the same exchange.
**Spec reference:** §8.4, §8.5
**Implementation plan:**
1. In `process_timed_request()`: Store the exchange_id and expiration time (`tasmota.millis() + timeout_ms`).
2. In `process_write_request()` and `process_invoke_request()`: If `query.timed_request == true`, verify that a matching timed request exists and hasn't expired. If not, return `TIMED_REQUEST_MISMATCH` (0xC9).
3. If `query.timed_request == false` but the operation requires a timed interaction (e.g., certain cluster commands), return `NEEDS_TIMED_INTERACTION` (0xC6).
**Suggested data structure:**
```berry
# In Matter_IM class
var timed_exchanges # map: exchange_id -> expiration_millis
def process_timed_request(msg, val)
var query = matter.TimedRequestMessage().from_TLV(val)
if self.timed_exchanges == nil self.timed_exchanges = {} end
self.timed_exchanges[msg.exchange_id] = tasmota.millis() + query.timeout
self.send_status(msg, matter.SUCCESS)
return true
end
def check_timed_interaction(msg, is_timed_request)
if !is_timed_request return true end # not a timed request, ok
if self.timed_exchanges == nil return false end
var expiry = self.timed_exchanges.find(msg.exchange_id)
self.timed_exchanges.remove(msg.exchange_id) # one-shot
if expiry == nil return false end
return !tasmota.time_reached(expiry)
end
```
---
### Change 4: Certificate Chain Validation in Sigma3 (MEDIUM Priority)
**Files affected:** `Matter_Commissioning_Context.be`
**Rationale:** The code has a TODO comment about verifying the NOC chain. While the signature is verified, the full chain (NOC → optional ICAC → RCAC) is not validated. This is a security gap.
**Spec reference:** §4.12 (Sigma3 Validation step 2)
**Implementation plan:**
1. After decrypting TBEData3, extract `initiatorNOC` and `initiatorICAC`.
2. Verify that `initiatorNOC` is signed by `initiatorICAC` (if present) or directly by the trusted RCAC.
3. Verify that `initiatorICAC` (if present) is signed by the trusted RCAC.
4. Verify that the Fabric ID in the NOC matches the session's fabric.
5. If any verification fails, send `StatusReport(FAILURE, SECURE_CHANNEL, INVALID_PARAMETER)`.
This is complex to implement in Berry due to X.509/Matter certificate parsing requirements. A pragmatic approach would be to at least verify the Fabric ID match (gap C3).
---
### Change 5: Operational Discovery TXT Records (LOW Priority)
**Files affected:** `Matter_z_Commissioning.be`
**Rationale:** Adding SII, SAI, T keys to operational discovery helps controllers optimize their retry behavior.
**Spec reference:** §4.3.2
**Implementation plan:**
In `mdns_announce_op_discovery()`, add TXT records:
```berry
var services = {
"SII": 500, # SESSION_IDLE_INTERVAL
"SAI": 300, # SESSION_ACTIVE_INTERVAL
"SAT": 4000, # SESSION_ACTIVE_THRESHOLD
"T": 0 # TCP support: 0 = no TCP
}
mdns.add_service("_matter", "_tcp", 5540, services, op_node, hostname)
```
---
## 5. Priority Summary
| Priority | Change | Impact | Effort |
|----------|--------|--------|--------|
| **HIGH** | Session parameter struct with mandatory fields (Change 1) | Compatibility with modern controllers | Medium |
| **HIGH** | ~~InteractionModelRevision = 12 (Change 2)~~ ✅ DONE | Spec compliance, controller compatibility | Trivial |
| MEDIUM | Timed interaction enforcement (Change 3) | Security compliance | Low |
| MEDIUM | Certificate chain validation (Change 4) | Security | High |
| LOW | Operational discovery TXT records (Change 5) | Better MRP behavior | Trivial |
---
## 6. What NOT to Change
- **Architecture**: The current layered design is clean and appropriate. No refactoring needed.
- **Solo fast-path**: The optimization for single reads/invokes is valuable on constrained hardware. Keep it.
- **Pull-mode ReportData**: Lazy attribute evaluation is memory-efficient. Keep it.
- **BDX/UDC**: Not needed for a basic Matter device. Keep them disabled.
- **Group messaging**: Not needed for typical Tasmota use cases. Keep it unimplemented.
- **TCP transport**: Not needed for a UDP-only device. Keep it unimplemented.
- **MAX_MESSAGE = 1150**: This is a good conservative value within the 1280 MTU limit.
- **Subscription max_interval = 60s**: This is a deliberate trade-off for responsiveness. Acceptable.
@@ -787,8 +787,8 @@ class Matter_IM
self.attributedata2raw(raw, ctx, res)
# add suffix 1824FF0118
raw.add(0x1824FF01, -4) # add 1824FF01
# add suffix 1824FF0C18
raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12
raw.add(0x18, 1) # add 18
elif ctx.status != nil
@@ -801,8 +801,8 @@ class Matter_IM
self.attributestatus2raw(raw, ctx, ctx.status)
# add suffix 1824FF0118
raw.add(0x1824FF01, -4) # add 1824FF01
# add suffix 1824FF0C18
raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12
raw.add(0x18, 1) # add 18
else
@@ -1022,8 +1022,8 @@ class Matter_IM
# ignore if content is nil and status is undefined
return false
end
# add suffix 1824FF0118
raw.add(0x1824FF01, -4) # add 1824FF01
# add suffix 1824FF0C18
raw.add(0x1824FF0C, -4) # add 1824FF0C - InteractionModelRevision 12
raw.add(0x18, 1) # add 18
# log(f"MTR: raw={raw.tohex()}", 3)
@@ -566,7 +566,7 @@ class Matter_IM_Message_base : Matter_IM_base
var InteractionModelRevision # 0xFF
def init()
self.InteractionModelRevision = 11 # 11 = Matter 1.2+ Interaction Model revision
self.InteractionModelRevision = 12 # 12 = Matter 1.4+ Interaction Model revision
end
end
@@ -811,7 +811,10 @@ class Matter_InvokeRequestMessage_solo : Matter_Path
# close
if raw.get(idx, -2) != 0x1818 return nil end
idx += 2
if raw.get(idx, -4) != 0x24FF0118 return nil end
# skip 24FFxx (InteractionModelRevision, any value)
if raw.get(idx, -2) == 0x24FF idx += 3 end
# expect 18
if raw.get(idx, 1) != 0x18 return nil end
# all good
return self
@@ -391,7 +391,7 @@ class Matter_IM_ReportData_Pull : Matter_IM_Message
end
# InteractionModelRevision
raw.add(0x24FF, -2) # add 24FF
raw.add(0x01, 1) # add 01
raw.add(0x0C, 1) # add 0C - InteractionModelRevision 12 (Matter 1.4+)
# close struct ReportDataMessage
raw.add(0x18, 1) # add 18
# log(f">>>: {raw.tohex()}", 3)
@@ -150,7 +150,7 @@ static const bvalue be_ktab_class_Matter_IM[203] = {
/* K141 */ be_nested_str_weak(expire_sendqueue),
/* K142 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand1_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s),
/* K143 */ be_const_int(354943030),
/* K144 */ be_const_int(405077761),
/* K144 */ be_const_int(405077772),
/* K145 */ be_nested_str_weak(build_response),
/* K146 */ be_nested_str_weak(message_handler),
/* K147 */ be_nested_str_weak(raw),
@@ -185,7 +185,7 @@ be_local_closure(class_Matter_IM_Message_base_init, /* name */
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[ 3]) { /* code */
0x5406000A, // 0000 LDINT R1 11
0x5406000B, // 0000 LDINT R1 12
0x90020001, // 0001 SETMBR R0 K0 R1
0x80000000, // 0002 RET 0
})
@@ -3286,8 +3286,8 @@ be_local_class(Matter_InvokeRequestMessage,
})),
be_str_weak(Matter_InvokeRequestMessage)
);
// compact class 'Matter_InvokeRequestMessage_solo' ktab size: 17, total: 20 (saved 24 bytes)
static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[17] = {
// compact class 'Matter_InvokeRequestMessage_solo' ktab size: 16, total: 19 (saved 24 bytes)
static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[16] = {
/* K0 */ be_nested_str_weak(reset),
/* K1 */ be_nested_str_weak(SuppressResponse),
/* K2 */ be_nested_str_weak(TimedRequest),
@@ -3304,7 +3304,6 @@ static const bvalue be_ktab_class_Matter_InvokeRequestMessage_solo[17] = {
/* K13 */ be_nested_str_weak(TLV),
/* K14 */ be_nested_str_weak(parse),
/* K15 */ be_nested_str_weak(next_idx),
/* K16 */ be_const_int(620691736),
};
@@ -3359,7 +3358,7 @@ be_local_closure(class_Matter_InvokeRequestMessage_solo_from_raw, /* name */
&be_ktab_class_Matter_InvokeRequestMessage_solo, /* shared constants */
be_str_weak(from_raw),
&be_const_str_solidified,
( &(const binstruction[170]) { /* code */
( &(const binstruction[179]) { /* code */
0x8C0C0100, // 0000 GETMET R3 R0 K0
0x7C0C0200, // 0001 CALL R3 1
0x600C000C, // 0002 GETGBL R3 G12
@@ -3523,13 +3522,22 @@ be_local_closure(class_Matter_InvokeRequestMessage_solo_from_raw, /* name */
0x00080506, // 00A0 ADD R2 R2 K6
0x8C140304, // 00A1 GETMET R5 R1 K4
0x5C1C0400, // 00A2 MOVE R7 R2
0x5421FFFB, // 00A3 LDINT R8 -4
0x5421FFFD, // 00A3 LDINT R8 -2
0x7C140600, // 00A4 CALL R5 3
0x20140B10, // 00A5 NE R5 R5 K16
0x78160001, // 00A6 JMPF R5 #00A9
0x4C140000, // 00A7 LDNIL R5
0x80040A00, // 00A8 RET 1 R5
0x80040000, // 00A9 RET 1 R0
0x541A24FE, // 00A5 LDINT R6 9471
0x1C140A06, // 00A6 EQ R5 R5 R6
0x78160000, // 00A7 JMPF R5 #00A9
0x00080507, // 00A8 ADD R2 R2 K7
0x8C140304, // 00A9 GETMET R5 R1 K4
0x5C1C0400, // 00AA MOVE R7 R2
0x58200005, // 00AB LDCONST R8 K5
0x7C140600, // 00AC CALL R5 3
0x541A0017, // 00AD LDINT R6 24
0x20140A06, // 00AE NE R5 R5 R6
0x78160001, // 00AF JMPF R5 #00B2
0x4C140000, // 00B0 LDNIL R5
0x80040A00, // 00B1 RET 1 R5
0x80040000, // 00B2 RET 1 R0
})
)
);
@@ -929,7 +929,7 @@ be_local_closure(class_Matter_IM_ReportData_Pull_send_im, /* name */
0x5431FFFD, // 014E LDINT R12 -2
0x7C240600, // 014F CALL R9 3
0x8C241123, // 0150 GETMET R9 R8 K35
0x582C0024, // 0151 LDCONST R11 K36
0x542E000B, // 0151 LDINT R11 12
0x58300024, // 0152 LDCONST R12 K36
0x7C240600, // 0153 CALL R9 3
0x8C241123, // 0154 GETMET R9 R8 K35