Matter read/write and commands (#18000)

This commit is contained in:
s-hadinger 2023-02-19 21:37:33 +01:00 committed by GitHub
parent a994c71de4
commit a26458a136
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 13060 additions and 8912 deletions

View File

@ -59,6 +59,8 @@ fprint("* Compact form for attributes and clusters")
fprint("*")
fprint("* Generated content, do not edit")
fprint("\\*********************************************************************************/")
fprint("#include <stddef.h>")
fprint("#include <stdint.h>")
fprint()
fprint("typedef struct {")
fprint(" uint16_t id;")
@ -89,7 +91,10 @@ for cl:cl_ids
var attr_ids_local = k2l(attr_id_name)
for attr_id:attr_ids_local
fprint(string.format(' { 0x%04X, %i, 0x%02X, "%s" },', attr_id, 0, 0, attributes[attr_id]['attributeName']))
var reportable = attributes[attr_id].find('reportable', false)
var writable = attributes[attr_id].find('writable', false)
var flags = (writable ? 0x01 : 0x00) | (reportable ? 0x02 : 0x00)
fprint(string.format(' { 0x%04X, %i, 0x%02X, "%s" },', attr_id, 0, flags, attributes[attr_id]['attributeName']))
end
fprint(' { 0xFFFF, 0, 0x00, NULL },')
fprint("};")

File diff suppressed because it is too large Load Diff

View File

@ -80,6 +80,34 @@ const char* matter_get_attribute_name(uint16_t cluster, uint16_t attribute) {
}
BE_FUNC_CTYPE_DECLARE(matter_get_attribute_name, "s", "ii")
bbool matter_is_attribute_writable(uint16_t cluster, uint16_t attribute) {
for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) {
if (cl->id == cluster) {
for (const matter_attribute_t * at = cl->attributes; at->id != 0xFFFF; at++) {
if (at->id == attribute) {
return (at->flags & 0x01) ? btrue : bfalse;
}
}
}
}
return bfalse;
}
BE_FUNC_CTYPE_DECLARE(matter_is_attribute_writable, "b", "ii")
bbool matter_is_attribute_reportable(uint16_t cluster, uint16_t attribute) {
for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) {
if (cl->id == cluster) {
for (const matter_attribute_t * at = cl->attributes; at->id != 0xFFFF; at++) {
if (at->id == attribute) {
return (at->flags & 0x02) ? btrue : bfalse;
}
}
}
}
return bfalse;
}
BE_FUNC_CTYPE_DECLARE(matter_is_attribute_reportable, "b", "ii")
const char* matter_get_command_name(uint16_t cluster, uint16_t command) {
for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) {
if (cl->id == cluster) {
@ -110,6 +138,8 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
#include "solidify/solidified_Matter_Commissioning.h"
#include "solidify/solidified_Matter_Message.h"
#include "solidify/solidified_Matter_MessageHandler.h"
#include "solidify/solidified_Matter_IM_Message.h"
#include "solidify/solidified_Matter_IM_Subscription.h"
#include "solidify/solidified_Matter_IM.h"
#include "solidify/solidified_Matter_Plugin.h"
#include "solidify/solidified_Matter_Base38.h"
@ -118,8 +148,8 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
#include "../generate/be_matter_certs.h"
#include "solidify/solidified_Matter_Plugin_core.h"
#include "solidify/solidified_Matter_Plugin_Relay.h"
#include "solidify/solidified_Matter_Plugin_Root.h"
#include "solidify/solidified_Matter_Plugin_OnOff.h"
/*********************************************************************************************\
* Get a bytes() object of the certificate DAC/PAI_Cert
@ -158,6 +188,8 @@ module matter (scope: global) {
get_cluster_name, ctype_func(matter_get_cluster_name)
get_attribute_name, ctype_func(matter_get_attribute_name)
is_attribute_writable, ctype_func(matter_is_attribute_writable)
is_attribute_reportable, ctype_func(matter_is_attribute_reportable)
get_command_name, ctype_func(matter_get_command_name)
get_opcode_name, ctype_func(matter_get_opcode_name)
TLV, class(be_class_Matter_TLV)
@ -247,9 +279,16 @@ module matter (scope: global) {
MessageHandler, class(be_class_Matter_MessageHandler)
// Interation Model
Response_container, class(be_class_Matter_Response_container)
Path, class(be_class_Matter_Path)
IM_Status, class(be_class_Matter_IM_Status)
IM_InvokeResponse, class(be_class_Matter_IM_InvokeResponse)
IM_WriteResponse, class(be_class_Matter_IM_WriteResponse)
IM_ReportData, class(be_class_Matter_IM_ReportData)
IM_ReportDataSubscribed, class(be_class_Matter_IM_ReportDataSubscribed)
IM_SubscribeResponse, class(be_class_Matter_IM_SubscribeResponse)
IM_Subscription, class(be_class_Matter_IM_Subscription)
IM_Subscription_Shop, class(be_class_Matter_IM_Subscription_Shop)
IM, class(be_class_Matter_IM)
Plugin_core, class(be_class_Matter_Plugin_core)
UI, class(be_class_Matter_UI)
// Base38 for QR Code
@ -265,11 +304,11 @@ module matter (scope: global) {
DAC_Cert_FFF1_8000, func(matter_DAC_Cert_FFF1_8000)
DAC_Pub_FFF1_8000, func(matter_DAC_Pub_FFF1_8000)
DAC_Priv_FFF1_8000, func(matter_DAC_Priv_FFF1_8000)
CD_FFF1_8000, func(matter_CD_FFF1_8000) // Certification Declaration
CD_FFF1_8000, func(matter_CD_FFF1_8000) // Certification Declaration
// Plugins
Plugin_core, class(be_class_Matter_Plugin_core) // Generic behavior common to all devices
Plugin_Relay, class(be_class_Matter_Plugin_Relay) // Relay behavior (OnOff)
Plugin_Root, class(be_class_Matter_Plugin_Root) // Generic behavior common to all devices
Plugin_OnOff, class(be_class_Matter_Plugin_OnOff) // Relay/Light behavior (OnOff)
}
@const_object_info_end */

View File

@ -113,9 +113,9 @@ class Matter_Commisioning_Context
pbkdfparamresp.responderSessionId = self.future_local_session_id
pbkdfparamresp.pbkdf_parameters_salt = self.device.salt
pbkdfparamresp.pbkdf_parameters_iterations = self.device.iterations
tasmota.log("MTR: pbkdfparamresp: " + str(matter.inspect(pbkdfparamresp)), 3)
tasmota.log("MTR: pbkdfparamresp: " + str(matter.inspect(pbkdfparamresp)), 4)
var pbkdfparamresp_raw = pbkdfparamresp.encode()
tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 3)
tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 4)
self.PBKDFParamResponse = pbkdfparamresp_raw
@ -134,22 +134,22 @@ class Matter_Commisioning_Context
var pake1 = matter.Pake1().parse(msg.raw, msg.app_payload_idx)
self.pA = pake1.pA
tasmota.log("MTR: received pA=" + self.pA.tohex(), 3)
tasmota.log("MTR: received pA=" + self.pA.tohex(), 4)
tasmota.log("MTR: spake: " + matter.inspect(self.spake), 3)
tasmota.log("MTR: spake: " + matter.inspect(self.spake), 4)
# instanciate SPAKE
self.spake = crypto.SPAKE2P_Matter(self.device.w0, self.device.w1, self.device.L)
# compute pB
self.spake.compute_pB(self.y)
self.pB = self.spake.pB
tasmota.log("MTR: y=" + self.y.tohex(), 3)
tasmota.log("MTR: pb=" + self.pB.tohex(), 3)
tasmota.log("MTR: y=" + self.y.tohex(), 4)
tasmota.log("MTR: pb=" + self.pB.tohex(), 4)
# compute ZV
self.spake.compute_ZV_verifier(self.pA)
tasmota.log("MTR: Z=" + self.spake.Z.tohex(), 3)
tasmota.log("MTR: V=" + self.spake.V.tohex(), 3)
tasmota.log("MTR: Z=" + self.spake.Z.tohex(), 4)
tasmota.log("MTR: V=" + self.spake.V.tohex(), 4)
var context = crypto.SHA256()
context.update(bytes().fromstring(self.Matter_Context_Prefix))
@ -157,7 +157,7 @@ class Matter_Commisioning_Context
context.update(self.PBKDFParamResponse)
var context_hash = context.out()
tasmota.log("MTR: Context=" + context_hash.tohex(), 3)
tasmota.log("MTR: Context=" + context_hash.tohex(), 4)
# add pA
self.spake.pA = self.pA
@ -165,35 +165,33 @@ class Matter_Commisioning_Context
self.spake.set_context(context_hash)
self.spake.compute_TT_hash(true) # `true` to indicate it's Matter variant to SPAKE2+
tasmota.log("MTR: ------------------------------", 3)
tasmota.log("MTR: Context = " + self.spake.Context.tohex(), 3)
tasmota.log("MTR: A = " + self.spake.A.tohex(), 3)
tasmota.log("MTR: B = " + self.spake.B.tohex(), 3)
tasmota.log("MTR: M = " + self.spake.M.tohex(), 3)
tasmota.log("MTR: N = " + self.spake.N.tohex(), 3)
tasmota.log("MTR: pA = " + self.spake.pA.tohex(), 3)
tasmota.log("MTR: pB = " + self.spake.pB.tohex(), 3)
tasmota.log("MTR: Z = " + self.spake.Z.tohex(), 3)
tasmota.log("MTR: V = " + self.spake.V.tohex(), 3)
tasmota.log("MTR: w0 = " + self.spake.w0.tohex(), 3)
tasmota.log("MTR: ------------------------------", 3)
tasmota.log("MTR: ------------------------------", 4)
tasmota.log("MTR: Context = " + self.spake.Context.tohex(), 4)
tasmota.log("MTR: M = " + self.spake.M.tohex(), 4)
tasmota.log("MTR: N = " + self.spake.N.tohex(), 4)
tasmota.log("MTR: pA = " + self.spake.pA.tohex(), 4)
tasmota.log("MTR: pB = " + self.spake.pB.tohex(), 4)
tasmota.log("MTR: Z = " + self.spake.Z.tohex(), 4)
tasmota.log("MTR: V = " + self.spake.V.tohex(), 4)
tasmota.log("MTR: w0 = " + self.spake.w0.tohex(), 4)
tasmota.log("MTR: ------------------------------", 4)
tasmota.log("MTR: Kmain =" + self.spake.Kmain.tohex(), 3)
tasmota.log("MTR: Kmain =" + self.spake.Kmain.tohex(), 4)
tasmota.log("MTR: KcA =" + self.spake.KcA.tohex(), 3)
tasmota.log("MTR: KcB =" + self.spake.KcB.tohex(), 3)
tasmota.log("MTR: K_shared=" + self.spake.K_shared.tohex(), 3)
tasmota.log("MTR: Ke =" + self.spake.Ke.tohex(), 3)
tasmota.log("MTR: KcA =" + self.spake.KcA.tohex(), 4)
tasmota.log("MTR: KcB =" + self.spake.KcB.tohex(), 4)
tasmota.log("MTR: K_shared=" + self.spake.K_shared.tohex(), 4)
tasmota.log("MTR: Ke =" + self.spake.Ke.tohex(), 4)
self.cB = self.spake.cB
self.Ke = self.spake.Ke
tasmota.log("MTR: cB=" + self.cB.tohex(), 3)
tasmota.log("MTR: cB=" + self.cB.tohex(), 4)
var pake2 = matter.Pake2()
pake2.pB = self.pB
pake2.cB = self.cB
tasmota.log("MTR: pake2: " + matter.inspect(pake2), 3)
tasmota.log("MTR: pake2: " + matter.inspect(pake2), 4)
var pake2_raw = pake2.encode()
tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 3)
tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 4)
# now package the response message
@ -212,7 +210,7 @@ class Matter_Commisioning_Context
var pake3 = matter.Pake3().parse(msg.raw, msg.app_payload_idx)
self.cA = pake3.cA
tasmota.log("MTR: received cA=" + self.cA.tohex(), 3)
tasmota.log("MTR: received cA=" + self.cA.tohex(), 4)
# check the value against computed
if self.cA != self.spake.cA raise "protocol_error", "invalid cA received" end
@ -224,12 +222,12 @@ class Matter_Commisioning_Context
self.R2IKey = session_keys[16..31]
self.AttestationChallenge = session_keys[32..47]
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: session_keys=" + session_keys.tohex(), 3)
tasmota.log("MTR: I2RKey =" + self.I2RKey.tohex(), 3)
tasmota.log("MTR: R2IKey =" + self.R2IKey.tohex(), 3)
tasmota.log("MTR: AC =" + self.AttestationChallenge.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: session_keys=" + session_keys.tohex(), 4)
tasmota.log("MTR: I2RKey =" + self.I2RKey.tohex(), 4)
tasmota.log("MTR: R2IKey =" + self.R2IKey.tohex(), 4)
tasmota.log("MTR: AC =" + self.AttestationChallenge.tohex(), 4)
tasmota.log("MTR: ******************************", 4)
# now package the response message
var resp = msg.build_response(0x40 #-StatusReport-#, false) # no reliable flag
@ -256,7 +254,7 @@ class Matter_Commisioning_Context
var destinationMessage = initiatorRandom + session.get_ca_pub() + session.get_fabric() + session.get_deviceid()
var key = session.get_ipk_group_key()
tasmota.log("MTR: SIGMA1: destinationMessage=" + destinationMessage.tohex(), 3)
tasmota.log("MTR: SIGMA1: key_ipk=" + key.tohex(), 3)
tasmota.log("MTR: SIGMA1: key_ipk=" + key.tohex(), 4)
var h = crypto.HMAC_SHA256(key)
h.update(destinationMessage)
var candidateDestinationId = h.out()
@ -315,12 +313,12 @@ class Matter_Commisioning_Context
var Resume1MICPayload = ec.decrypt(encrypted)
var decrypted_tag = ec.tag()
tasmota.log("****************************************", 3)
tasmota.log("MTR: * s1rk = " + s1rk.tohex(), 3)
tasmota.log("MTR: * tag = " + tag.tohex(), 3)
tasmota.log("MTR: * Resume1MICPayload = " + Resume1MICPayload.tohex(), 3)
tasmota.log("MTR: * decrypted_tag = " + decrypted_tag.tohex(), 3)
tasmota.log("****************************************", 3)
tasmota.log("****************************************", 4)
tasmota.log("MTR: * s1rk = " + s1rk.tohex(), 4)
tasmota.log("MTR: * tag = " + tag.tohex(), 4)
tasmota.log("MTR: * Resume1MICPayload = " + Resume1MICPayload.tohex(), 4)
tasmota.log("MTR: * decrypted_tag = " + decrypted_tag.tohex(), 4)
tasmota.log("****************************************", 4)
if tag == decrypted_tag
# Generate and Send Sigma2_Resume
session.resumption_id = crypto.random(16) # generate a new resumption id
@ -349,15 +347,15 @@ class Matter_Commisioning_Context
var ac = session_keys[32..47]
var session_timestamp = tasmota.rtc()['utc']
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3)
tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3)
tasmota.log("MTR: AC =" + ac.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: I2RKey =" + i2r.tohex(), 4)
tasmota.log("MTR: R2IKey =" + r2i.tohex(), 4)
tasmota.log("MTR: AC =" + ac.tohex(), 4)
tasmota.log("MTR: ******************************", 4)
var sigma2resume_raw = sigma2resume.encode()
session._Msg1 = nil
tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 3)
tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 4)
# now package the response message
var resp = msg.build_response(0x33 #-sigma-2-resume-#, true)
@ -365,7 +363,7 @@ class Matter_Commisioning_Context
self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter)
session.close()
# session.close()
session.set_keys(i2r, r2i, ac, session_timestamp)
session.set_persist(true) # keep session on flash
session.set_no_expiration() # never expire
@ -402,9 +400,9 @@ class Matter_Commisioning_Context
sigma2_tbedata.add_TLV(4, matter.TLV.B2, session.resumption_id)
# compute TranscriptHash = Crypto_Hash(message = Msg1)
tasmota.log("****************************************", 3)
tasmota.log("****************************************", 4)
session._Msg1 = sigma1.Msg1
tasmota.log("MTR: * MSG1 = " + session._Msg1.tohex(), 3)
tasmota.log("MTR: * MSG1 = " + session._Msg1.tohex(), 4)
var TranscriptHash = crypto.SHA256().update(session._Msg1).out()
# Compute S2K, p.175
@ -412,27 +410,27 @@ class Matter_Commisioning_Context
var s2k_salt = session.get_ipk_group_key() + responderRandom + self.ResponderEph_pub + TranscriptHash
var s2k = crypto.HKDF_SHA256().derive(session.shared_secret, s2k_salt, s2k_info, 16)
tasmota.log("MTR: * SharedSecret = " + session.shared_secret.tohex(), 3)
tasmota.log("MTR: * s2k_salt = " + s2k_salt.tohex(), 3)
tasmota.log("MTR: * s2k = " + s2k.tohex(), 3)
tasmota.log("MTR: * SharedSecret = " + session.shared_secret.tohex(), 4)
tasmota.log("MTR: * s2k_salt = " + s2k_salt.tohex(), 4)
tasmota.log("MTR: * s2k = " + s2k.tohex(), 4)
var sigma2_tbedata_raw = sigma2_tbedata.encode()
# // `AES_CCM.init(secret_key:bytes(16 or 32), iv:bytes(7..13), aad:bytes(), data_len:int, tag_len:int) -> instance`
var aes = crypto.AES_CCM(s2k, bytes().fromstring(self.TBEData2_Nonce), bytes(), size(sigma2_tbedata_raw), 16)
var TBEData2Encrypted = aes.encrypt(sigma2_tbedata_raw) + aes.tag()
tasmota.log("MTR: * TBEData2Enc = " + TBEData2Encrypted.tohex(), 3)
tasmota.log("****************************************", 3)
tasmota.log("MTR: * TBEData2Enc = " + TBEData2Encrypted.tohex(), 4)
tasmota.log("****************************************", 4)
var sigma2 = matter.Sigma2()
sigma2.responderRandom = responderRandom
sigma2.responderSessionId = self.future_local_session_id
sigma2.responderEphPubKey = self.ResponderEph_pub
sigma2.encrypted2 = TBEData2Encrypted
tasmota.log("MTR: sigma2: " + matter.inspect(sigma2), 3)
tasmota.log("MTR: sigma2: " + matter.inspect(sigma2), 4)
var sigma2_raw = sigma2.encode()
session._Msg2 = sigma2_raw
tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 3)
tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 4)
# now package the response message
var resp = msg.build_response(0x31 #-sigma-2-#, true) # no reliable flag
@ -454,23 +452,23 @@ class Matter_Commisioning_Context
var session = msg.session
var sigma3 = matter.Sigma3().parse(msg.raw, msg.app_payload_idx)
tasmota.log("****************************************", 3)
tasmota.log("****************************************", 4)
# compute TranscriptHash = Crypto_Hash(message = Msg1 || Msg2)
var TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).out()
tasmota.log("MTR: * session = " + str(session), 3)
tasmota.log("MTR: session.ipk_epoch_key " + str(session.ipk_epoch_key), 3)
tasmota.log("MTR: session.fabric_compressed " + str(session.fabric_compressed), 3)
tasmota.log("MTR: * ipk_group_key = " + session.get_ipk_group_key().tohex(), 3)
tasmota.log("MTR: * TranscriptHash= " + TranscriptHash.tohex(), 3)
tasmota.log("MTR: * session = " + str(session), 4)
tasmota.log("MTR: session.ipk_epoch_key " + str(session.ipk_epoch_key), 4)
tasmota.log("MTR: session.fabric_compressed " + str(session.fabric_compressed), 4)
tasmota.log("MTR: * ipk_group_key = " + session.get_ipk_group_key().tohex(), 4)
tasmota.log("MTR: * TranscriptHash= " + TranscriptHash.tohex(), 4)
var s3k_info = bytes().fromstring(self.S3K_Info)
var s3k = crypto.HKDF_SHA256().derive(session.shared_secret, session.get_ipk_group_key() + TranscriptHash, s3k_info, 16)
tasmota.log("****************************************", 3)
tasmota.log("****************************************", 4)
# self.ipk_epoch_key == nil || self.fabric_compressed")
tasmota.log("MTR: * s3k_salt = " + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3)
tasmota.log("MTR: * s3k = " + s3k.tohex(), 3)
tasmota.log("****************************************", 3)
tasmota.log("MTR: * s3k_salt = " + (session.get_ipk_group_key() + TranscriptHash).tohex(), 4)
tasmota.log("MTR: * s3k = " + s3k.tohex(), 4)
tasmota.log("****************************************", 4)
# decrypt
var encrypted = sigma3.TBEData3Encrypted[0..-17]
@ -478,10 +476,10 @@ class Matter_Commisioning_Context
var ec = crypto.AES_CCM(s3k, bytes().fromstring(self.TBEData3_Nonce), bytes(), size(encrypted), 16)
var TBEData3 = ec.decrypt(encrypted)
var TBETag3 = ec.tag()
tasmota.log("MTR: * TBEData3 = " + TBEData3.tohex(), 3)
tasmota.log("MTR: * TBETag3 = " + TBETag3.tohex(), 3)
tasmota.log("MTR: * tag_sent = " + tag.tohex(), 3)
tasmota.log("****************************************", 3)
tasmota.log("MTR: * TBEData3 = " + TBEData3.tohex(), 4)
tasmota.log("MTR: * TBETag3 = " + TBETag3.tohex(), 4)
tasmota.log("MTR: * tag_sent = " + tag.tohex(), 4)
tasmota.log("****************************************", 4)
if TBETag3 != tag raise "value_error", "tag do not match" end
@ -507,9 +505,9 @@ class Matter_Commisioning_Context
sigma3_tbs.add_TLV(4, matter.TLV.B1, self.ResponderEph_pub)
var sigma3_tbs_raw = sigma3_tbs.encode()
tasmota.log("MTR: * initiatorNOCPubKey = " + initiatorNOCPubKey.tohex(), 3)
tasmota.log("MTR: * ec_signature = " + ec_signature.tohex(), 3)
tasmota.log("****************************************", 3)
tasmota.log("MTR: * initiatorNOCPubKey = " + initiatorNOCPubKey.tohex(), 4)
tasmota.log("MTR: * ec_signature = " + ec_signature.tohex(), 4)
tasmota.log("****************************************", 4)
# `crypto.EC_P256().ecdsa_verify_sha256(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool`
var sigma3_tbs_valid = crypto.EC_P256().ecdsa_verify_sha256(initiatorNOCPubKey, sigma3_tbs_raw, ec_signature)
@ -524,9 +522,9 @@ class Matter_Commisioning_Context
session._Msg1 = nil
session._Msg2 = nil
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: shared_secret =" + session.shared_secret.tohex(), 3)
tasmota.log("MTR: ipk + hash =" + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: shared_secret =" + session.shared_secret.tohex(), 4)
tasmota.log("MTR: ipk + hash =" + (session.get_ipk_group_key() + TranscriptHash).tohex(), 4)
# compute session key
var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#,
session.get_ipk_group_key() + TranscriptHash #- salt -#,
@ -537,11 +535,11 @@ class Matter_Commisioning_Context
var ac = session_keys[32..47]
var session_timestamp = tasmota.rtc()['utc']
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3)
tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3)
tasmota.log("MTR: AC =" + ac.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: I2RKey =" + i2r.tohex(), 4)
tasmota.log("MTR: R2IKey =" + r2i.tohex(), 4)
tasmota.log("MTR: AC =" + ac.tohex(), 4)
tasmota.log("MTR: ******************************", 4)
# Send success status report
var resp = msg.build_response(0x40 #-StatusReport-#, true) # reliable flag

View File

@ -98,7 +98,7 @@ class Matter_Pake1
def parse(b, idx)
if idx == nil idx = 0 end
var val = matter.TLV.parse(b, idx)
tasmota.log("MTR: parsed TLV: " + str(val), 3)
tasmota.log("MTR: parsed TLV: " + str(val), 4)
self.pA = val.getsubval(1)
return self
@ -130,7 +130,7 @@ class Matter_Pake3
def parse(b, idx)
if idx == nil idx = 0 end
var val = matter.TLV.parse(b, idx)
tasmota.log("MTR: parsed TLV: " + str(val), 3)
tasmota.log("MTR: parsed TLV: " + str(val), 4)
self.cA = val.getsubval(1)
return self
@ -157,7 +157,7 @@ class Matter_Sigma1
if idx == nil idx = 0 end
var val = matter.TLV.parse(b, idx)
self.Msg1 = b[idx..]
tasmota.log("MTR: Sigma1 TLV=" + str(val), 3)
tasmota.log("MTR: Sigma1 TLV=" + str(val), 4)
self.initiatorRandom = val.getsubval(1)
self.initiator_session_id = val.getsubval(2)
@ -240,7 +240,7 @@ class Matter_Sigma3
if idx == nil idx = 0 end
var val = matter.TLV.parse(b, idx)
self.Msg3 = b[idx..]
tasmota.log("MTR: Sigma3 TLV=" + str(val), 3)
tasmota.log("MTR: Sigma3 TLV=" + str(val), 4)
self.TBEData3Encrypted = val.getsubval(1)
return self

View File

@ -28,7 +28,7 @@ class Matter_Device
static var FILENAME = "_matter_device.json"
var plugins # list of plugins
var udp_server # `matter.UDPServer()` object
var msg_handler # `matter.MessageHandler()` object
var message_handler # `matter.MessageHandler()` object
var sessions # `matter.Session_Store()` objet
var ui
# information about the device
@ -65,12 +65,12 @@ class Matter_Device
self.sessions = matter.Session_Store()
self.sessions.load()
self.msg_handler = matter.MessageHandler(self)
self.message_handler = matter.MessageHandler(self)
self.ui = matter.UI(self)
# add the default plugin
self.plugins.push(matter.Plugin_core(self))
self.plugins.push(matter.Plugin_Relay(self))
self.plugins.push(matter.Plugin_Root(self))
self.plugins.push(matter.Plugin_OnOff(self))
self.start_mdns_announce_hostnames()
@ -167,7 +167,7 @@ class Matter_Device
# dispatch every second click to sub-objects that need it
def every_second()
self.sessions.every_second()
self.msg_handler.every_second()
self.message_handler.every_second()
end
#############################################################
@ -178,7 +178,7 @@ class Matter_Device
#############################################################
# callback when message is received
def msg_received(raw, addr, port)
return self.msg_handler.msg_received(raw, addr, port)
return self.message_handler.msg_received(raw, addr, port)
end
def msg_send(raw, addr, port, id)
@ -214,27 +214,6 @@ class Matter_Device
tasmota.set_timer(0, /-> self.start_commissioning_complete(session))
end
#############################################################
# Start UDP mDNS announcements for commissioning
#
# eth is `true` if ethernet turned up, `false` is wifi turned up
# def mdns_announce_commissioning()
# var services = {
# "VP":str(self.vendorid) + "+" + str(self.productid),
# "D": self.discriminator,
# "CM":1, # requires passcode
# "T":0, # no support for TCP
# "SII":5000, "SAI":300
# }
# if self.self.hostname_eth
# mdns.add_service("_matterc","_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth)
# end
# if self.self.hostname_wifi
# mdns.add_service("_matter","_tcp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi)
# end
# end
#############################################################
# Start Operational Discovery
def start_operational_dicovery(session)
@ -265,28 +244,36 @@ class Matter_Device
tasmota.log("MTR: *** Commissioning complete ***", 2)
end
#############################################################
# read an attribute
#
# def read_attribute(msg, ctx)
# # dispatch only to plugins that support this endpoint and cluster
# var endpoint = ctx.endpoint
# var cluster = ctx.cluster
# var idx = 0
# while idx < size(self.plugins)
# var plugin = self.plugins[idx]
# if plugin.has(cluster, endpoint)
# var ret = plugin.read_attribute(msg, ctx)
# if ret != nil
# return ret
# end
# end
# idx += 1
# end
# end
#################################################################################
# Simple insertion sort - sorts the list in place, and returns the list
# remove duplicates
#################################################################################
static def sort_distinct(l)
# insertion sort
for i:1..size(l)-1
var k = l[i]
var j = i
while (j > 0) && (l[j-1] > k)
l[j] = l[j-1]
j -= 1
end
l[j] = k
end
# remove duplicate now that it's sorted
var i = 1
if size(l) <= 1 return l end # no duplicate if empty or 1 element
var prev = l[0]
while i < size(l)
if l[i] == prev
l.remove(i)
else
prev = l[i]
i += 1
end
end
return l
end
#############################################################
# expand attribute list based
@ -294,69 +281,94 @@ class Matter_Device
# called only when expansion is needed,
# so we don't need to report any error since they are ignored
def process_attribute_expansion(ctx, cb)
#################################################################################
# Returns the keys of a map as a sorted list
#################################################################################
def keys_sorted(m)
var l = []
for k: m.keys()
l.push(k)
end
# insertion sort
for i:1..size(l)-1
var k = l[i]
var j = i
while (j > 0) && (l[j-1] > k)
l[j] = l[j-1]
j -= 1
end
l[j] = k
end
return l
end
import string
var endpoint = ctx.endpoint
var endpoint_mono = [ endpoint ]
# var endpoint_mono = [ endpoint ]
var endpoint_found = false # did any endpoint match
var cluster = ctx.cluster
var cluster_mono = [ cluster ]
# var cluster_mono = [ cluster ]
var cluster_found = false
var attribute = ctx.attribute
var attribute_mono = [ attribute ]
# var attribute_mono = [ attribute ]
var attribute_found = false
var direct = (ctx.endpoint != nil) && (ctx.cluster != nil) && (ctx.attribute != nil) # true if the target is a precise attribute, false if it results from an expansion and error are ignored
tasmota.log(string.format("MTR: process_attribute_expansion %s", str(ctx)), 3)
tasmota.log(string.format("MTR: process_attribute_expansion %s", str(ctx)), 4)
# build the list of candidates
# list of all endpoints
var all = {} # map of {endpoint: {cluster: {attributes:[pi]}}
tasmota.log(string.format("MTR: endpoint=%s cluster=%s attribute=%s", endpoint, cluster, attribute), 4)
for pi: self.plugins
var ep_list = pi.get_endpoints() # get supported endpoints for this plugin
tasmota.log(string.format("MTR: ep_list %s %s", str(pi), str(ep_list)), 3)
if endpoint != nil
# we have a specific endpoint, make sure it's in the list
if ep_list.find(endpoint) != nil
ep_list = endpoint_mono
endpoint_found = true
else
continue
end
end
# ep_list is the actual list of candidate endpoints for this plugin
# iterate on endpoints
tasmota.log(string.format("MTR: pi=%s ep_list=%s", str(pi), str(ep_list)), 4)
for ep: ep_list
# now filter on clusters
var cluster_list = pi.get_cluster_list(ep)
tasmota.log(string.format("MTR: cluster_list %s %s", str(ep), str(cluster_list)), 3)
if cluster != nil
# we have a specific cluster, make sure it's in the list
if cluster_list.find(cluster) != nil
cluster_list = cluster_mono
cluster_found = true
else
continue
if endpoint != nil && ep != endpoint continue end # skip if specific endpoint and no match
# from now on, 'ep' is a good candidate
if !all.contains(ep) all[ep] = {} end # create empty structure if not already in the list
endpoint_found = true
# now explore the cluster list for 'ep'
var cluster_list = pi.get_cluster_list(ep) # cluster_list is the actual list of candidate cluster for this pluging and endpoint
tasmota.log(string.format("MTR: pi=%s ep=%s cl_list=%s", str(pi), str(ep), str(cluster_list)), 4)
for cl: cluster_list
if cluster != nil && cl != cluster continue end # skip if specific cluster and no match
# from now on, 'cl' is a good candidate
if !all[ep].contains(cl) all[ep][cl] = {} end
cluster_found = true
# now filter on attributes
var attr_list = pi.get_attribute_list(ep, cl)
tasmota.log(string.format("MTR: pi=%s ep=%s cl=%s at_list=%s", str(pi), str(ep), str(cl), str(attr_list)), 4)
for at: attr_list
if attribute != nil && at != attribute continue end # skip if specific attribiute and no match
# from now on, 'at' is a good candidate
if !all[ep][cl].contains(at) all[ep][cl][at] = [] end
attribute_found = true
all[ep][cl][at].push(pi) # add plugin to the list
end
end
# cluster_list is the actual list of candidate cluster for this pluging and endpoint
for cl: cluster_list
# now filter on attribute
var attr_list = pi.get_attribute_list(ep, cluster)
tasmota.log(string.format("MTR: attr_list %s %s", str(cl), str(attr_list)), 3)
if attribute != nil
# we have a specific attribute, make sure it's in the list
if attr_list.find(attribute) != nil
attr_list = attribute_mono
attribute_found = true
else
continue
end
for at: attr_list
# we now have the complete candidate: ep/cl/at
tasmota.log(string.format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3)
ctx.endpoint = ep
ctx.cluster = cl
ctx.attribute = at
var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context
if finished return end
end
end
end
# import json
# tasmota.log("MTR: all = " + json.dump(all), 2)
# iterate on candidates
for ep: keys_sorted(all)
for cl: keys_sorted(all[ep])
for at: keys_sorted(all[ep][cl])
for pi: all[ep][cl][at]
tasmota.log(string.format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3)
ctx.endpoint = ep
ctx.cluster = cl
ctx.attribute = at
var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context
if direct && finished return end
end
end
end

View File

@ -19,50 +19,21 @@
import matter
#@ solidify:Matter_Response_container,weak
#@ solidify:Matter_IM,weak
#################################################################################
# Matter_Response_container
#
# Used to store all the elements of the reponse to an attribute or command
#################################################################################
class Matter_Response_container
var endpoint
var cluster
var attribute
var command
var status
def tostring()
try
import string
var s = ""
s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]")
s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/")
s += (self.attribute != nil ? string.format("%04X", self.attribute) : "")
s += (self.command != nil ? string.format("%04X", self.attribute) : "")
return s
except .. as e, m
return "Exception> " + str(e) + ", " + str(m)
end
end
end
matter.Response_container = Matter_Response_container
#################################################################################
# Matter_IM class
#################################################################################
class Matter_IM
static var MAX_MESSAGE = 1200
static var MSG_TIMEOUT = 10000 # 10s
var responder
var device
var subs # subscriptions shop
def init(responder, device)
self.responder = responder
var send_queue # list of IM_Message queued for sending as part of exchange-id
def init(device)
self.device = device
self.send_queue = []
self.subs = matter.IM_Subscription_Shop(self)
end
def process_incoming(msg)
@ -74,7 +45,7 @@ class Matter_IM
tasmota.log("MTR: IM TLV: " + str(val), 3)
var InteractionModelRevision = val.findsubval(0xFF)
tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 3)
tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 4)
var opcode = msg.opcode
if opcode == 0x01 # Status Response
@ -102,26 +73,71 @@ class Matter_IM
return false
end
#############################################################
# send enqueued responses
#
def send_enqueued(responder)
var idx = 0
while idx < size(self.send_queue)
var message = self.send_queue[idx]
if message.ready
var finish = message.send(responder) # send message
if finish
self.send_queue.remove(idx)
idx -= 1
else
message.ready = false # needs more to proceed
end
end
idx += 1
end
end
#############################################################
# find in send_queue by exchangeid
#
def find_sendqueue_by_exchangeid(exchangeid)
if exchangeid == nil return nil end
var idx = 0
while idx < size(self.send_queue)
var message = self.send_queue[idx]
if message.get_exchangeid() == exchangeid
return message
end
idx += 1
end
return nil
end
#############################################################
# process IM 0x01 Status Response
#
# val is the TLV structure
# returns `true` if processed, `false` if silently ignored,
# or raises an exception
def process_status_response(msg, val)
import string
var status = val.findsubval(0, 0xFF)
tasmota.log(string.format("MTR: Status Response = 0x%02X", status), 3)
return true
if status == matter.SUCCESS
tasmota.log("MTR: >Status", 2) # don't show 'SUCCESS' to not overflow logs with non-information
var message = self.find_sendqueue_by_exchangeid(msg.exchange_id)
if message
message.ack_received(msg) # re-arm the sending of next packets for the same exchange
return true
end
else
tasmota.log(string.format("MTR: >Status ERROR = 0x%02X", status), 2)
end
return false
end
#############################################################
# process IM 0x02 Read Request
# Inner code shared between read_attributes and subscribe_request
#
# val is the TLV structure
# returns `true` if processed, `false` if silently ignored,
# or raises an exception
def process_read_request(msg, val)
# query: `ReadRequestMessage` or `SubscribeRequestMessage`
def _inner_process_read_request(msg, query)
var endpoints = self.device.get_active_endpoints()
### Inner function to be iterated upon
@ -150,7 +166,7 @@ class Matter_IM
a1.attribute_data.data = res
ret.attribute_reports.push(a1)
tasmota.log(string.format("MTR: Read_Attr %s%s - %s", str(ctx), attr_name, str(res)), 2)
tasmota.log(string.format("MTR: Read_Attr %s%s - %s", str(ctx), attr_name, str(res)), 2)
return true # stop expansion since we have a value
elif ctx.status != nil
if direct
@ -164,105 +180,89 @@ class Matter_IM
a1.attribute_status.status.status = ctx.status
ret.attribute_reports.push(a1)
tasmota.log(string.format("MTR: Read_Attr %s%s - STATUS: 0x%02X %s", str(ctx), attr_name, ctx.status, ctx.status == matter.UNSUPPORTED_ATTRIBUTE ? "UNSUPPORTED_ATTRIBUTE" : ""), 2)
tasmota.log(string.format("MTR: Read_Attr %s%s - STATUS: 0x%02X %s", str(ctx), attr_name, ctx.status, ctx.status == matter.UNSUPPORTED_ATTRIBUTE ? "UNSUPPORTED_ATTRIBUTE" : ""), 2)
return true
end
else
tasmota.log(string.format("MTR: Read_Attr %s%s - IGNORED", str(ctx), attr_name), 2)
tasmota.log(string.format("MTR: Read_Attr %s%s - IGNORED", str(ctx), attr_name), 2)
# ignore if content is nil and status is undefined
return false
end
end
# structure is `ReadRequestMessage` 10.6.2 p.558
tasmota.log("MTR: IM:read_request processing start", 3)
var ctx = matter.Response_container()
var ctx = matter.Path()
var query = matter.ReadRequestMessage().from_TLV(val)
if query.attributes_requests != nil
# prepare the response
var ret = matter.ReportDataMessage()
# ret.suppress_response = true
ret.attribute_reports = []
# prepare the response
var ret = matter.ReportDataMessage()
# ret.suppress_response = true
ret.attribute_reports = []
for q:query.attributes_requests
# need to do expansion here
ctx.endpoint = q.endpoint
ctx.cluster = q.cluster
ctx.attribute = q.attribute
ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil`
# expand endpoint
if ctx.endpoint == nil || ctx.cluster == nil || ctx.attribute == nil
# we need expansion, log first
if ctx.cluster != nil && ctx.attribute != nil
var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute)
tasmota.log("MTR: Read_Attr " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2)
else
tasmota.log("MTR: Read_Attr " + str(ctx), 2)
end
for q:query.attributes_requests
# need to do expansion here
ctx.endpoint = q.endpoint
ctx.cluster = q.cluster
ctx.attribute = q.attribute
ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil`
# expand endpoint
if ctx.endpoint == nil || ctx.cluster == nil || ctx.attribute == nil
# we need expansion, log first
if ctx.cluster != nil && ctx.attribute != nil
var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute)
tasmota.log("MTR: Read_Attr " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2)
else
tasmota.log("MTR: Read_Attr " + str(ctx), 2)
end
# implement concrete expansion
self.device.process_attribute_expansion(ctx,
/ pi, ctx, direct -> read_single_attribute(ret, pi, ctx, direct)
)
end
tasmota.log("MTR: ReportDataMessage=" + str(ret), 3)
tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3)
# implement concrete expansion
self.device.process_attribute_expansion(ctx,
/ pi, ctx, direct -> read_single_attribute(ret, pi, ctx, direct)
)
end
# send the reponse that may need to be chunked if too large to fit in a single UDP message
self.send_attr_report(msg, ret)
tasmota.log("MTR: ReportDataMessage=" + str(ret), 4)
tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3)
return ret
end
#############################################################
# process IM 0x02 Read Request
#
# val is the TLV structure
# returns `true` if processed, `false` if silently ignored,
# or raises an exception
def process_read_request(msg, val)
var query = matter.ReadRequestMessage().from_TLV(val)
if query.attributes_requests != nil
var ret = self._inner_process_read_request(msg, query)
self.send_report_data(msg, ret)
end
return true
end
def send_attr_report(msg, ret)
# class to keep the current chunked reponse
class Matter_Attr_Report
var ret # return structure as ReportDataMessage TLV structure
var resp # response Frame (to keep all fields like session or remote_ip/port)
var expiration
end
# compute the acceptable size
var msg_sz = 0
var elements = 0
if size(ret.attribute_reports) > 0
msg_sz = size(ret.attribute_reports[0].to_TLV().encode())
elements = 1
end
while msg_sz < self.MAX_MESSAGE && elements < size(ret.attribute_reports)
var next_sz = size(ret.attribute_reports[elements].to_TLV().encode())
if msg_sz + next_sz < self.MAX_MESSAGE
msg_sz += next_sz
elements += 1
end
end
var next_elemnts = ret.attribute_reports[elements .. ]
ret.attribute_reports = ret.attribute_reports[0 .. elements - 1]
if size(next_elemnts) > 0
ret.more_chunked_messages = true
end
var resp = msg.build_response(0x05 #-Report Data-#, true)
resp.encode(ret.to_TLV().encode()) # payload in cleartext
resp.encrypt()
self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter)
if size(next_elemnts) > 0
ret.attribute_reports = next_elemnts
var chunked_next = Matter_Attr_Report()
chunked_next.ret = ret
chunked_next.resp = resp
chunked_next.expiration = tasmota.millis() + self.MSG_TIMEOUT
#############################################################
# process IM 0x03 Subscribe Request
#
def subscribe_request(msg, val)
import string
var query = matter.SubscribeRequestMessage().from_TLV(val)
if !query.keep_subscriptions
self.subs.remove_by_session(msg.session) # if `keep_subscriptions`, kill all subscriptions from current session
end
tasmota.log("MTR: received SubscribeRequestMessage=" + str(query), 3)
var sub = self.subs.new_subscription(msg.session, query)
var ret = self._inner_process_read_request(msg, query)
# ret is of type `Matter_ReportDataMessage`
ret.subscription_id = sub.subscription_id # enrich with subscription id TODO
self.send_subscribe_response(msg, ret, sub)
return true
end
#############################################################
@ -274,8 +274,8 @@ class Matter_IM
def process_invoke_request(msg, val)
import string
# structure is `ReadRequestMessage` 10.6.2 p.558
tasmota.log("MTR: IM:invoke_request processing start", 3)
var ctx = matter.Response_container()
tasmota.log("MTR: IM:invoke_request processing start", 4)
var ctx = matter.Path()
var query = matter.InvokeRequestMessage().from_TLV(val)
if query.invoke_requests != nil
@ -291,11 +291,19 @@ class Matter_IM
ctx.status = matter.UNSUPPORTED_COMMAND #default error if returned `nil`
var cmd_name = matter.get_command_name(ctx.cluster, ctx.command)
if cmd_name == nil cmd_name = string.format("0x%04X/0x02X", ctx.cluster, ctx.command) end
tasmota.log(string.format("MTR: >Received_cmd %s from [%s]:%i", cmd_name, msg.remote_ip, msg.remote_port), 2)
var res = self.responder.device.invoke_request(msg, q.command_fields, ctx)
tasmota.log(string.format("MTR: >Received %s %s from [%s]:%i", str(ctx), cmd_name ? cmd_name : "", msg.remote_ip, msg.remote_port), 2)
var res = self.device.invoke_request(msg, q.command_fields, ctx)
var a1 = matter.InvokeResponseIB()
if res != nil
if res == true # special case, just respond ok
a1.status = matter.CommandStatusIB()
a1.status.command_path = matter.CommandPathIB()
a1.status.command_path.endpoint = ctx.endpoint
a1.status.command_path.cluster = ctx.cluster
a1.status.command_path.command = ctx.command
a1.status.status = matter.StatusIB()
a1.status.status.status = matter.SUCCESS
ret.invoke_responses.push(a1)
elif res != nil
a1.command = matter.CommandDataIB()
a1.command.command_path = matter.CommandPathIB()
a1.command.command_path.endpoint = ctx.endpoint
@ -305,8 +313,7 @@ class Matter_IM
ret.invoke_responses.push(a1)
cmd_name = matter.get_command_name(ctx.cluster, ctx.command)
if cmd_name == nil cmd_name = string.format("0x%04X/0x%02X", ctx.cluster, ctx.command) end
tasmota.log(string.format("MTR: <Replied_cmd %s", cmd_name), 2)
tasmota.log(string.format("MTR: <Replied %s %s", str(ctx), cmd_name ? cmd_name : ""), 2)
elif ctx.status != nil
a1.status = matter.CommandStatusIB()
a1.status.command_path = matter.CommandPathIB()
@ -321,43 +328,26 @@ class Matter_IM
end
end
tasmota.log("MTR: invoke_responses="+str(ret.invoke_responses), 3)
tasmota.log("MTR: invoke_responses="+str(ret.invoke_responses), 4)
if size(ret.invoke_responses) > 0
tasmota.log("MTR: InvokeResponse=" + str(ret), 3)
tasmota.log("MTR: InvokeResponse=" + str(ret), 4)
tasmota.log("MTR: InvokeResponseTLV=" + str(ret.to_TLV()), 3)
var resp = msg.build_response(0x09 #-Invoke Response-#, true)
resp.encode(ret.to_TLV().encode()) # payload in cleartext
resp.encrypt()
self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter)
elif msg.x_flag_r # nothing to respond, check if we need a standalone ack
var resp = msg.build_standalone_ack()
resp.encode()
resp.encrypt()
# no ecnryption required for ACK
self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter)
self.send_invoke_response(msg, ret)
else
return false # we don't send anything, hence the responder sends a simple packet ack
end
return true
end
end
#############################################################
# process IM 0x03 Subscribe Request
#
def subscribe_request(msg, val)
import string
var query = matter.SubscribeRequestMessage().from_TLV(val)
tasmota.log("MTR: received SubscribeRequestMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x04 Subscribe Response
#
def subscribe_response(msg, val)
import string
var query = matter.SubscribeResponseMessage().from_TLV(val)
tasmota.log("MTR: received SubscribeResponsetMessage=" + str(query), 3)
tasmota.log("MTR: received SubscribeResponsetMessage=" + str(query), 2)
return false
end
@ -367,7 +357,7 @@ class Matter_IM
def report_data(msg, val)
import string
var query = matter.ReportDataMessage().from_TLV(val)
tasmota.log("MTR: received ReportDataMessage=" + str(query), 3)
tasmota.log("MTR: received ReportDataMessage=" + str(query), 2)
return false
end
@ -378,7 +368,100 @@ class Matter_IM
import string
var query = matter.WriteRequestMessage().from_TLV(val)
tasmota.log("MTR: received WriteRequestMessage=" + str(query), 3)
return false
var suppress_response = query.suppress_response
# var timed_request = query.timed_request # TODO not supported
# var more_chunked_messages = query.more_chunked_messages # TODO not supported
var endpoints = self.device.get_active_endpoints()
### Inner function to be iterated upon
# ret is the ReportDataMessage list to send back
# ctx is the context with endpoint/cluster/attribute
# val is the TLV object containing the value
# direct is true if error is reported, false if error is silently ignored
#
# if `pi` is nil, just report the status for ctx.status
#
# should return true if answered, false if failed
def write_single_attribute(ret, pi, ctx, write_data, direct)
import string
var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute)
attr_name = attr_name ? " (" + attr_name + ")" : ""
# tasmota.log(string.format("MTR: Read Attribute " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2)
# Special case to report unsupported item, if pi==nil
ctx.status = matter.UNSUPPORTED_WRITE
var res = (pi != nil) ? pi.write_attribute(msg, ctx, write_data) : nil
if res ctx.status = matter.SUCCESS end # if the cb returns true, the request was processed
if ctx.status != nil
if direct
var a1 = matter.AttributeStatusIB()
a1.path = matter.AttributePathIB()
a1.status = matter.StatusIB()
a1.path.endpoint = ctx.endpoint
a1.path.cluster = ctx.cluster
a1.path.attribute = ctx.attribute
a1.status.status = ctx.status
ret.write_responses.push(a1)
tasmota.log(string.format("MTR: Write_Attr %s%s - STATUS: 0x%02X %s", str(ctx), attr_name, ctx.status, ctx.status == matter.SUCCESS ? "SUCCESS" : ""), 2)
return true
end
else
tasmota.log(string.format("MTR: Write_Attr %s%s - IGNORED", str(ctx), attr_name), 2)
# ignore if content is nil and status is undefined
end
end
# structure is `ReadRequestMessage` 10.6.2 p.558
tasmota.log("MTR: IM:write_request processing start", 4)
var ctx = matter.Path()
if query.write_requests != nil
# prepare the response
var ret = matter.WriteResponseMessage()
# ret.suppress_response = true
ret.write_responses = []
for q:query.write_requests # q is AttributeDataIB
var path = q.path
var write_data = q.data
# need to do expansion here
ctx.endpoint = path.endpoint
ctx.cluster = path.cluster
ctx.attribute = path.attribute
ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil`
# return an error if the expansion is illegal
if ctx.cluster == nil || ctx.attribute == nil
# force INVALID_ACTION reporting
ctx.status = matter.INVALID_ACTION
write_single_attribute(ret, nil, ctx, nil, true)
continue
end
# expand endpoint
if ctx.endpoint == nil
# we need expansion, log first
var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute)
tasmota.log("MTR: Write_Attr " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2)
end
# implement concrete expansion
self.device.process_attribute_expansion(ctx,
/ pi, ctx, direct -> write_single_attribute(ret, pi, ctx, write_data, direct)
)
end
tasmota.log("MTR: ReportWriteMessage=" + str(ret), 4)
tasmota.log("MTR: ReportWriteMessageTLV=" + str(ret.to_TLV()), 3)
# send the reponse that may need to be chunked if too large to fit in a single UDP message
if !suppress_response
self.send_write_response(msg, ret)
end
end
return true
end
#############################################################
@ -387,7 +470,7 @@ class Matter_IM
def process_write_response(msg, val)
import string
var query = matter.WriteResponseMessage().from_TLV(val)
tasmota.log("MTR: received WriteResponseMessage=" + str(query), 3)
tasmota.log("MTR: received WriteResponseMessage=" + str(query), 2)
return false
end
@ -397,7 +480,7 @@ class Matter_IM
def process_invoke_response(msg, val)
import string
var query = matter.InvokeResponseMessage().from_TLV(val)
tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 3)
tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 2)
return false
end
@ -409,22 +492,70 @@ class Matter_IM
var query = matter.TimedRequestMessage().from_TLV(val)
tasmota.log("MTR: received TimedRequestMessage=" + str(query), 3)
tasmota.log(string.format("MTR: >Received_IM TimedRequest=%i from [%s]:%i", query.timeout, msg.remote_ip, msg.remote_port), 2)
tasmota.log(string.format("MTR: >Received TimedRequest=%i from [%s]:%i", query.timeout, msg.remote_ip, msg.remote_port), 2)
# Send success status report
var sr = matter.StatusResponseMessage()
sr.status = matter.SUCCESS
var resp = msg.build_response(0x01 #-Status Response-#, true #-reliable-#)
resp.encode(sr.to_TLV().encode()) # payload in cleartext
resp.encrypt()
self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter)
self.send_status(msg, matter.SUCCESS)
return true
end
#############################################################
# send regular update for data subscribed
#
def send_subscribe_update(sub)
import string
var session = sub.session
var ret = matter.ReportDataMessage()
ret.subscription_id = sub.subscription_id
ret.attribute_reports = []
ret.suppress_response = true # true for empy report, as per 8.6.2 p.425
self.send_queue.push(matter.IM_ReportDataSubscribed(self.device.message_handler, session, ret))
self.send_enqueued(self.device.message_handler)
end
#############################################################
# send_status
#
def send_status(msg, status)
self.send_queue.push(matter.IM_Status(msg, status))
end
#############################################################
# send_invoke_response
#
def send_invoke_response(msg, data)
self.send_queue.push(matter.IM_InvokeResponse(msg, data))
end
#############################################################
# send_invoke_response
#
def send_write_response(msg, data)
self.send_queue.push(matter.IM_WriteResponse(msg, data))
end
#############################################################
# send_report_data
#
def send_report_data(msg, data)
self.send_queue.push(matter.IM_ReportData(msg, data))
end
#############################################################
# send_report_data
#
def send_subscribe_response(msg, data, sub)
self.send_queue.push(matter.IM_SubscribeResponse(msg, data, sub))
end
#############################################################
# placeholder, nothing to run for now
def every_second()
self.subs.every_second()
end
end
matter.IM = Matter_IM

View File

@ -670,7 +670,7 @@ class Matter_SubscribeRequestMessage : Matter_IM_Message_base
var keep_subscriptions # bool
var min_interval_floor # u16
var max_interval_ceiling # u16
var attribute_requests # array of AttributePathIB
var attributes_requests # array of AttributePathIB
var event_requests # array of EventPathIB
var event_filters # array of EventFilterIB
var fabric_filtered # bool
@ -679,13 +679,13 @@ class Matter_SubscribeRequestMessage : Matter_IM_Message_base
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.keep_subscriptions = val.findsubval(0)
self.min_interval_floor = val.findsubval(1)
self.max_interval_ceiling = val.findsubval(2)
self.attribute_requests = self.from_TLV_array(val.findsubval(3), matter.AttributePathIB)
self.keep_subscriptions = val.findsubval(0, false)
self.min_interval_floor = val.findsubval(1, 0)
self.max_interval_ceiling = val.findsubval(2, 60)
self.attributes_requests = self.from_TLV_array(val.findsubval(3), matter.AttributePathIB)
self.event_requests = self.from_TLV_array(val.findsubval(4), matter.EventPathIB)
self.event_filters = self.from_TLV_array(val.findsubval(5), matter.EventFilterIB)
self.fabric_filtered = val.findsubval(7)
self.fabric_filtered = val.findsubval(7, false)
self.data_version_filters = self.from_TLV_array(val.findsubval(8), matter.DataVersionFilterIB)
return self
end
@ -696,7 +696,7 @@ class Matter_SubscribeRequestMessage : Matter_IM_Message_base
s.add_TLV(0, TLV.BOOL, self.keep_subscriptions)
s.add_TLV(1, TLV.U2, self.min_interval_floor)
s.add_TLV(2, TLV.U2, self.max_interval_ceiling)
self.to_TLV_array(s, 3, self.attribute_requests)
self.to_TLV_array(s, 3, self.attributes_requests)
self.to_TLV_array(s, 4, self.event_requests)
self.to_TLV_array(s, 5, self.event_filters)
s.add_TLV(7, TLV.BOOL, self.fabric_filtered)

View File

@ -0,0 +1,281 @@
#
# Matter_IM_Message.be - suppport for Matter Interaction Model messages responses
#
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import matter
#@ solidify:Matter_Path,weak
#@ solidify:Matter_IM_Message,weak
#@ solidify:Matter_IM_Status,weak
#@ solidify:Matter_IM_InvokeResponse,weak
#@ solidify:Matter_IM_WriteResponse,weak
#@ solidify:Matter_IM_ReportData,weak
#@ solidify:Matter_IM_ReportDataSubscribed,weak
#@ solidify:Matter_IM_SubscribeResponse,weak
#################################################################################
# Matter_Path
#
# Used to store all the elements of the reponse to an attribute or command
#################################################################################
class Matter_Path
var endpoint # endpoint or `nil` if expansion
var cluster # cluster or `nil` if expansion
var attribute # attribute or `nil` if expansion
var command # command
var status # status to be returned (matter.SUCCESS or matter.<ERROR>)
def tostring()
try
import string
var s = ""
s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]")
s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/")
s += (self.attribute != nil ? string.format("%04X", self.attribute) : "")
s += (self.command != nil ? string.format("%04X", self.command) : "")
if self.attribute == nil && self.command == nil s += "****" end
return s
except .. as e, m
return "Exception> " + str(e) + ", " + str(m)
end
end
end
matter.Path = Matter_Path
#################################################################################
# Matter_IM_Message
#
# Superclass for all IM responses
#################################################################################
class Matter_IM_Message
var resp # response Frame object
var ready # bool: ready to send (true) or wait (false)
var data # TLV data of the response (if any)
# build a response message stub
def init(msg, opcode, reliable)
self.resp = msg.build_response(opcode, reliable)
self.ready = true
end
# ack received for previous message, proceed to next (if any)
def ack_received(msg)
self.resp = msg.build_response(self.resp.opcode, self.resp.x_flag_r, self.resp) # update packet
self.ready = true
end
# get the exchange-id for this message
def get_exchangeid()
return self.resp.exchange_id
end
# return true if transaction is complete (remove object from queue)
# default responder for data
def send(responder)
var resp = self.resp
resp.encode(self.data.to_TLV().encode()) # payload in cleartext
resp.encrypt()
responder.send_response(resp.raw, resp.remote_ip, resp.remote_port, resp.message_counter)
return true
end
end
matter.IM_Message = Matter_IM_Message
#################################################################################
# Matter_IM_Status
#
# Send a simple Status Message
#################################################################################
class Matter_IM_Status : Matter_IM_Message
def init(msg, status)
super(self).init(msg, 0x01 #-Status Response-#, true #-reliable-#)
var sr = matter.StatusResponseMessage()
sr.status = status
self.data = sr
self.ready = true # send immediately
end
end
matter.IM_Status = Matter_IM_Status
#################################################################################
# Matter_IM_InvokeResponse
#
# Send a simple Status Message
#################################################################################
class Matter_IM_InvokeResponse : Matter_IM_Message
def init(msg, data)
super(self).init(msg, 0x09 #-Invoke Response-#, true)
self.data = data
self.ready = true # send immediately
end
end
matter.IM_InvokeResponse = Matter_IM_InvokeResponse
#################################################################################
# Matter_IM_WriteResponse
#
# Send a simple Status Message
#################################################################################
class Matter_IM_WriteResponse : Matter_IM_Message
def init(msg, data)
super(self).init(msg, 0x07 #-Write Response-#, true)
self.data = data
self.ready = true # send immediately
end
end
matter.IM_WriteResponse = Matter_IM_WriteResponse
#################################################################################
# Matter_IM_ReportData
#
# Report Data for a Read Request
#################################################################################
class Matter_IM_ReportData : Matter_IM_Message
static var MAX_MESSAGE = 1200 # max bytes size for a single TLV worklaod
static var MSG_TIMEOUT = 10000 # 10s
var expiration # expiration time for the reporting
def init(msg, data)
super(self).init(msg, 0x05 #-Report Data-#, true)
self.data = data
self.ready = true # send immediately
self.expiration = tasmota.millis() + self.MSG_TIMEOUT
end
# return true if transaction is complete (remove object from queue)
# default responder for data
def send(responder)
import string
var resp = self.resp
var ret = self.data
var was_chunked = ret.more_chunked_messages # is this following a chunked packet?
# compute the acceptable size
var msg_sz = 0
var elements = 0
if size(ret.attribute_reports) > 0
msg_sz = ret.attribute_reports[0].to_TLV().encode_len()
elements = 1
end
while msg_sz < self.MAX_MESSAGE && elements < size(ret.attribute_reports)
var next_sz = ret.attribute_reports[elements].to_TLV().encode_len()
if msg_sz + next_sz < self.MAX_MESSAGE
msg_sz += next_sz
elements += 1
else
break
end
end
tasmota.log(string.format("MTR: elements=%i msg_sz=%i total=%i", elements, msg_sz, size(ret.attribute_reports)), 3)
var next_elemnts = ret.attribute_reports[elements .. ]
ret.attribute_reports = ret.attribute_reports[0 .. elements - 1]
ret.more_chunked_messages = (size(next_elemnts) > 0)
if was_chunked
tasmota.log(string.format("MTR: Read_Attr next_chunk exch=%i", self.get_exchangeid()), 3)
end
if ret.more_chunked_messages
if !was_chunked
tasmota.log(string.format("MTR: Read_Attr first_chunk exch=%i", self.get_exchangeid()), 3)
end
tasmota.log("MTR: sending TLV" + str(ret), 3)
end
resp.encode(self.data.to_TLV().encode()) # payload in cleartext
resp.encrypt()
responder.send_response(resp.raw, resp.remote_ip, resp.remote_port, resp.message_counter)
if size(next_elemnts) > 0
ret.attribute_reports = next_elemnts
tasmota.log("MTR: to_be_sent_later TLV" + str(ret), 3)
self.expiration = tasmota.millis() + self.MSG_TIMEOUT # give more time
return false # keep alive
else
return true # finished, remove
end
end
end
matter.IM_ReportData = Matter_IM_ReportData
#################################################################################
# Matter_IM_ReportDataSubscribed
#
# Main difference is that we are the spontaneous inititor
#################################################################################
class Matter_IM_ReportDataSubscribed : Matter_IM_ReportData
def init(message_handler, session, data)
self.resp = matter.Frame.initiate_response(message_handler, session, 0x05 #-Report Data-#, true)
self.data = data
self.ready = true # send immediately
self.expiration = tasmota.millis() + self.MSG_TIMEOUT
end
end
matter.IM_ReportDataSubscribed = Matter_IM_ReportDataSubscribed
#################################################################################
# Matter_IM_SubscribeResponse
#
# Report Data for a Read Request
#################################################################################
class Matter_IM_SubscribeResponse : Matter_IM_ReportData
var sub # subscription object
var report_data_phase # true during reportdata
def init(msg, data, sub)
super(self).init(msg, data)
self.sub = sub
self.report_data_phase = true
end
# return true if transaction is complete (remove object from queue)
# default responder for data
def send(responder)
if self.report_data_phase
var ret = super(self).send(responder)
if !ret return false end # ReportData needs to continue
# ReportData is finished
self.report_data_phase = false
return false
else
# send the final SubscribeReponse
var resp = self.resp
var sr = matter.SubscribeResponseMessage()
sr.subscription_id = self.sub.subscription_id
sr.max_interval = self.sub.max_interval
self.resp.opcode = 0x04 #- Subscribe Response -#
resp.encode(sr.to_TLV().encode()) # payload in cleartext
resp.encrypt()
responder.send_response(resp.raw, resp.remote_ip, resp.remote_port, resp.message_counter)
return true
end
end
end
matter.IM_SubscribeResponse = Matter_IM_SubscribeResponse

View File

@ -0,0 +1,180 @@
#
# Matter_IM_Subscription.be - suppport for Matter Interaction Model subscriptions
#
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import matter
#@ solidify:Matter_IM_Subscription,weak
#@ solidify:Matter_IM_Subscription_Shop,weak
#################################################################################
# Matter_IM_Subscription
#
# Individual subscription instance
#################################################################################
class Matter_IM_Subscription
static var MAX_INTERVAL_MARGIN = 10 # we always keep 10s margin
# parameters of the subscription
var subscription_id # id of the subcription as known by requester
var session # the session it belongs to
var path_list # list of path subscibed to
var min_interval # never send data more often than every `min_interval` seconds
var max_interval # always send data before `max_interal` seconds or the subscription is lost
var fabric_filtered
# manage time
var expiration # expiration epoch, we need to respond before
# updates
var updates
# req: SubscribeRequestMessage
def init(id, session, req)
self.subscription_id = id
self.session = session
# check values for min_interval
var min_interval = req.min_interval_floor
if min_interval < 0 min_interval = 0 end
if min_interval > 60 min_interval = 60 end
self.min_interval = min_interval
# check values for max_interval
var max_interval = req.max_interval_ceiling
if max_interval < 60 max_interval = 60 end
if max_interval > 3600 max_interval = 3600 end
self.max_interval = max_interval
self.fabric_filtered = req.fabric_filtered
# get list of path from
self.path_list = []
for q: req.attributes_requests
var ctx = matter.Path()
ctx.endpoint = q.endpoint
ctx.cluster = q.cluster
ctx.attribute = q.attribute
self.path_list.push(ctx)
end
# update next time interval
self.updates = []
self.clear_and_arm()
tasmota.log("MTR: new subsctiption " + matter.inspect(self), 2)
end
# clear log after it was sent, and re-arm next expiration
def clear_and_arm()
self.updates.clear()
self.expiration = tasmota.millis() + (self.max_interval - self.MAX_INTERVAL_MARGIN) * 1000
end
# signal that an attribute was updated, to add to the list of reportable
def attribute_updated(ctx, fabric_specific)
var idx = 0
while idx < size(self.path_list)
var filter = self.path_list[idx]
if (filter.endpoint == nil || filter.endpoint == ctx.endpoint) &&
(filter.cluster == nil || filter.cluster == ctx.cluster) &&
(filter.attribute == nil || filter.attribute == ctx.attribute)
self.updates.push(ctx)
end
idx += 1
end
end
end
matter.IM_Subscription = Matter_IM_Subscription
#################################################################################
# Matter_IM_Subscription_Shop (monad)
#
# Handles all subscriptions
#################################################################################
class Matter_IM_Subscription_Shop
var subs # list of subscriptions
var im # pointer to parent `im` object
def init(im)
self.im = im
self.subs = []
end
#############################################################
# create a new subscription
#
# session object
# SubscribeRequestMessage request
# returns: new subscription
def new_subscription(session, req)
import crypto
var id = crypto.random(2).get(0,2)
while self.get_by_id(id)
id = crypto.random(2).get(0,2)
end
var sub = matter.IM_Subscription(id, session, req)
self.subs.push(sub)
return sub
end
def get_by_id(id)
var idx = 0
while idx < size(self.subs)
if self.subs[idx].subscription_id == id
return self.subs[idx]
end
idx += 1
end
end
def remove_by_session(session)
var idx = 0
while idx < size(self.subs)
if self.subs[idx].session == session
self.subs.remove(idx)
else
idx += 1
end
end
end
def every_second()
var idx = 0
while idx < size(self.subs)
var sub = self.subs[idx]
if tasmota.time_reached(sub.expiration)
self.im.send_subscribe_update(sub)
sub.clear_and_arm()
end
idx += 1
end
end
# signal that an attribute was updated, to add to the list of reportable
def attribute_updated(ctx, fabric_specific)
# signal any relevant subscription
var idx = 0
while idx < size(self.subs)
self.subs[idx].attribute_updated(ctx, fabric_specific)
idx += 1
end
end
end
matter.IM_Subscription_Shop = Matter_IM_Subscription_Shop

View File

@ -232,6 +232,9 @@ class Matter_Frame
# send back response
var resp = classof(self)(self.message_handler)
resp.remote_ip = self.remote_ip
resp.remote_port = self.remote_port
if self.flag_s
resp.flag_dsiz = 0x01
resp.dest_node_id_8 = self.source_node_id
@ -249,19 +252,23 @@ class Matter_Frame
resp.protocol_id = 0 # PROTOCOL_ID_SECURE_CHANNEL
resp.x_flag_a = 1 # ACK of previous message
resp.ack_message_counter = self.message_counter
resp.x_flag_r = 0
resp.x_flag_r = 1
tasmota.log(string.format("MTR: <Replied %s", matter.get_opcode_name(resp.opcode)), 2)
tasmota.log(string.format("MTR: <Replied %s", matter.get_opcode_name(resp.opcode)), 3)
return resp
end
#############################################################
# Generate response to message with default parameter
# does not handle encryption which is done in a later step
def build_response(opcode, reliable)
#
# if 'resp' is not nil, update frame
def build_response(opcode, reliable, resp)
import string
# send back response
var resp = classof(self)(self.message_handler)
if resp == nil
resp = classof(self)(self.message_handler)
end
resp.remote_ip = self.remote_ip
resp.remote_port = self.remote_port
@ -296,11 +303,47 @@ class Matter_Frame
if resp.local_session_id == 0
var op_name = matter.get_opcode_name(resp.opcode)
if !op_name op_name = string.format("0x%02X", resp.opcode) end
tasmota.log(string.format("MTR: <Replied %s", op_name), 2)
tasmota.log(string.format("MTR: <Replied %s", op_name), 2)
end
return resp
end
#############################################################
# Generate a message - we are the initiator
#
# if 'resp' is not nil, update frame
static def initiate_response(message_handler, session, opcode, reliable, resp)
import string
# send back response
if resp == nil
resp = matter.Frame(message_handler)
end
resp.remote_ip = session.__ip
resp.remote_port = session.__port
resp.flag_dsiz = 0x00
resp.session = session # also copy the session object
# message counter
if session && session.initiator_session_id != 0
resp.message_counter = session.counter_snd.next()
resp.local_session_id = session.initiator_session_id
else
resp.message_counter = session._counter_insecure_snd.next()
resp.local_session_id = 0
end
resp.x_flag_i = 1 # we are the initiator
resp.opcode = opcode
session.__exchange_id += 1 # move to next exchange_id
resp.exchange_id = session.__exchange_id
resp.protocol_id = 0x0001 # PROTOCOL_ID_INTERACTION_MODEL
resp.x_flag_r = reliable ? 1 : 0
return resp
end
#############################################################
# decrypt with I2S key
# return cleartext or `nil` if failed
@ -340,22 +383,22 @@ class Matter_Frame
n.resize(13) # add zeros
end
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: i2r =" + i2r.tohex(), 3)
tasmota.log("MTR: p =" + p.tohex(), 3)
tasmota.log("MTR: a =" + a.tohex(), 3)
tasmota.log("MTR: n =" + n.tohex(), 3)
tasmota.log("MTR: mic =" + mic.tohex(), 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: i2r =" + i2r.tohex(), 4)
tasmota.log("MTR: p =" + p.tohex(), 4)
tasmota.log("MTR: a =" + a.tohex(), 4)
tasmota.log("MTR: n =" + n.tohex(), 4)
tasmota.log("MTR: mic =" + mic.tohex(), 4)
# decrypt
var aes = crypto.AES_CCM(i2r, n, a, size(p), 16)
var cleartext = aes.decrypt(p)
var tag = aes.tag()
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: cleartext =" + cleartext.tohex(), 3)
tasmota.log("MTR: tag =" + tag.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: cleartext =" + cleartext.tohex(), 4)
tasmota.log("MTR: tag =" + tag.tohex(), 4)
tasmota.log("MTR: ******************************", 4)
if tag != mic
tasmota.log("MTR: rejected packet due to invalid MIC", 3)
@ -389,30 +432,30 @@ class Matter_Frame
end
n.resize(13) # add zeros
tasmota.log("MTR: cleartext: " + self.raw.tohex(), 3)
tasmota.log("MTR: cleartext: " + self.raw.tohex(), 4)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: r2i =" + r2i.tohex(), 3)
tasmota.log("MTR: p =" + p.tohex(), 3)
tasmota.log("MTR: a =" + a.tohex(), 3)
tasmota.log("MTR: n =" + n.tohex(), 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: r2i =" + r2i.tohex(), 4)
tasmota.log("MTR: p =" + p.tohex(), 4)
tasmota.log("MTR: a =" + a.tohex(), 4)
tasmota.log("MTR: n =" + n.tohex(), 4)
# decrypt
var aes = crypto.AES_CCM(r2i, n, a, size(p), 16)
var ciphertext = aes.encrypt(p)
var tag = aes.tag()
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ciphertext =" + ciphertext.tohex(), 3)
tasmota.log("MTR: tag =" + tag.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: ******************************", 4)
tasmota.log("MTR: ciphertext =" + ciphertext.tohex(), 4)
tasmota.log("MTR: tag =" + tag.tohex(), 4)
tasmota.log("MTR: ******************************", 4)
# packet is good, put back content in raw
self.raw.resize(self.payload_idx) # remove cleartext payload
self.raw .. ciphertext # add ciphertext
self.raw .. tag # add MIC
# tasmota.log("MTR: encrypted: " + self.raw.tohex(), 3)
# tasmota.log("MTR: encrypted: " + self.raw.tohex(), 4)
end
#############################################################
@ -421,7 +464,7 @@ class Matter_Frame
var r = matter.Frame(self.message_handler, raw)
r.decode_header()
r.decode_payload()
tasmota.log("MTR: sending decode: " + matter.inspect(r), 3)
tasmota.log("MTR: sending decode: " + matter.inspect(r), 4)
end
end
matter.Frame = Matter_Frame

View File

@ -35,7 +35,7 @@ class Matter_MessageHandler
def init(device)
self.device = device
self.commissioning = matter.Commisioning_Context(self)
self.im = matter.IM(self, device)
self.im = matter.IM(device)
self.counter_rcv = matter.Counter()
end
@ -47,6 +47,8 @@ class Matter_MessageHandler
#
def msg_received(raw, addr, port)
import string
var ret = false
try
tasmota.log("MTR: MessageHandler::msg_received raw="+raw.tohex(), 4)
var frame = matter.Frame(self, raw, addr, port)
@ -60,6 +62,8 @@ class Matter_MessageHandler
### unencrypted session, handled by commissioning
var session = self.device.sessions.find_session_source_id_unsecure(frame.source_node_id, 90) # 90 seconds max
tasmota.log("MTR: find session by source_node_id = " + str(frame.source_node_id) + "session_id = " + str(session.local_session_id), 3)
if addr session.__ip = addr end
if port session.__port = port end
frame.session = session
# check if it's a duplicate
@ -73,7 +77,7 @@ class Matter_MessageHandler
if frame.opcode != 0x10 # don't show `MRP_Standalone_Acknowledgement`
var op_name = matter.get_opcode_name(frame.opcode)
if !op_name op_name = string.format("0x%02X", frame.opcode) end
tasmota.log(string.format("MTR: >Received %s from [%s]:%i", op_name, addr, port), 2)
tasmota.log(string.format("MTR: >Received %s from [%s]:%i", op_name, addr, port), 2)
end
self.commissioning.process_incoming(frame, addr, port)
return true
@ -88,6 +92,8 @@ class Matter_MessageHandler
tasmota.log("MTR: frame="+matter.inspect(frame), 3)
return false
end
if addr session.__ip = addr end
if port session.__port = port end
frame.session = session # keep a pointer of the session in the message
# check if it's a duplicate
@ -106,7 +112,7 @@ class Matter_MessageHandler
# continue decoding
tasmota.log(string.format("MTR: idx=%i clear=%s", frame.payload_idx, frame.raw.tohex()), 3)
frame.decode_payload()
tasmota.log("MTR: decrypted message: protocol_id:"+str(frame.protocol_id)+" opcode="+str(frame.opcode)+" exchange_id"+str(frame.exchange_id), 3)
tasmota.log("MTR: decrypted message: protocol_id:"+str(frame.protocol_id)+" opcode="+str(frame.opcode)+" exchange_id="+str(frame.exchange_id), 3)
self.device.packet_ack(frame.ack_message_counter) # acknowledge packet
@ -117,10 +123,22 @@ class Matter_MessageHandler
tasmota.log("MTR: PROTOCOL_ID_SECURE_CHANNEL " + matter.inspect(frame), 3)
# if frame.opcode == 0x10
# end
return true
ret = true
elif protocol_id == 0x0001 # PROTOCOL_ID_INTERACTION_MODEL
# dispatch to IM Protocol Messages
return self.im.process_incoming(frame, addr, port)
ret = self.im.process_incoming(frame, addr, port)
# if `ret` is true, we have something to send
if ret
self.im.send_enqueued(self)
elif frame.x_flag_r # nothing to respond, check if we need a standalone ack
var resp = frame.build_standalone_ack()
resp.encode()
resp.encrypt()
# no ecnryption required for ACK
self.send_response(resp.raw, resp.remote_ip, resp.remote_port, resp.message_counter)
# send simple ack
end
# -- PROTOCOL_ID_BDX is used for file transfer between devices, not used in Tasmota
# elif protocol_id == 0x0002 # PROTOCOL_ID_BDX -- BDX not handled at all in Tasmota
@ -132,12 +150,11 @@ class Matter_MessageHandler
# return false # ignore for now TODO
else
tasmota.log("MTR: ignoring unhandled protocol_id:"+str(protocol_id), 3)
return false
end
end
return true
return ret
except .. as e, m
tasmota.log("MTR: MessageHandler::msg_received exception: "+str(e)+";"+str(m))
import debug

View File

@ -91,7 +91,7 @@ class Matter_Plugin
#############################################################
# write attribute
def write_attribute(msg, endpoint, cluster, attribute)
def write_attribute(msg, ctx, write_data)
return nil
end

View File

@ -0,0 +1,156 @@
#
# Matter_Plugin_OnOff.be - implements the behavior for a Relay (OnOff)
#
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Matter plug-in for core behavior
# dummy declaration for solidification
class Matter_Plugin end
#@ solidify:Matter_Plugin_OnOff,weak
class Matter_Plugin_OnOff : Matter_Plugin
static var ENDPOINTS = [ 1 ]
static var CLUSTERS = {
0x001D: [0,1,2,3], # Descriptor Cluster 9.5 p.453
0x0003: [0,1], # Identify 1.2 p.16
0x0004: [0], # Groups 1.3 p.21
0x0005: [0,1,2,3,4,5], # Scenes 1.4 p.30 - no writable
0x0006: [0,0xFFFC] # On/Off 1.5 p.48
}
static var TYPES = [ 0x0100 ] # On/Off Light
var onoff # fake status for now # TODO
#############################################################
# Constructor
def init(device)
super(self).init(device)
self.endpoints = self.ENDPOINTS
self.clusters = self.CLUSTERS
self.onoff = false # fake status for now # TODO
end
#############################################################
# read an attribute
#
def read_attribute(msg, ctx)
import string
var TLV = matter.TLV
var cluster = ctx.cluster
var attribute = ctx.attribute
if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ----------
var dtl = TLV.Matter_TLV_array()
for dt: self.TYPES
var d1 = dtl.add_struct()
d1.add_TLV(0, TLV.U2, dt) # DeviceType
d1.add_TLV(1, TLV.U2, 1) # Revision
end
return dtl
elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ----------
var sl = TLV.Matter_TLV_array()
for cl: self.get_cluster_list()
sl.add_TLV(nil, TLV.U4, cl)
end
return sl
elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ----------
var cl = TLV.Matter_TLV_array()
cl.add_TLV(nil, TLV.U2, 0x0006)
return cl
elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]----------
var pl = TLV.Matter_TLV_array()
return pl
end
# ====================================================================================================
elif cluster == 0x0003 # ========== Identify 1.2 p.16 ==========
if attribute == 0x0000 # ---------- IdentifyTime / u2 ----------
return TLV.create_TLV(TLV.U2, 0) # no identification in progress
elif attribute == 0x0001 # ---------- IdentifyType / enum8 ----------
return TLV.create_TLV(TLV.U1, 0) # IdentifyType = 0x00 None
end
# ====================================================================================================
elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ==========
if attribute == 0x0000 # ---------- OnOff / bool ----------
return TLV.create_TLV(TLV.BOOL, self.onoff)
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting
end
end
# no match found, return that the attribute is unsupported end
end
#############################################################
# Invoke a command
#
# returns a TLV object if successful, contains the response
# or an `int` to indicate a status
def invoke_request(msg, val, ctx)
var TLV = matter.TLV
var cluster = ctx.cluster
var command = ctx.command
var session = msg.session
# ====================================================================================================
if cluster == 0x0003 # ========== Identify 1.2 p.16 ==========
if command == 0x0000 # ---------- Identify ----------
# ignore
return true
elif command == 0x0001 # ---------- IdentifyQuery ----------
# create IdentifyQueryResponse
# ID=1
# 0=Certificate (octstr)
var iqr = TLV.Matter_TLV_struct()
iqr.add_TLV(0, TLV.U2, 0) # Timeout
ctx.command = 0x00 # IdentifyQueryResponse
return iqr
elif command == 0x0040 # ---------- TriggerEffect ----------
# ignore
return true
end
# ====================================================================================================
elif cluster == 0x0004 # ========== Groups 1.3 p.21 ==========
# TODO
return true
# ====================================================================================================
elif cluster == 0x0005 # ========== Scenes 1.4 p.30 ==========
# TODO
return true
# ====================================================================================================
elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ==========
if command == 0x0000 # ---------- Off ----------
self.onoff = false
return true
elif command == 0x0001 # ---------- On ----------
self.onoff = true
return true
elif command == 0x0002 # ---------- Toggle ----------
self.onoff = !self.onoff
return true
end
end
end
end
matter.Plugin_OnOff = Matter_Plugin_OnOff

View File

@ -1,93 +0,0 @@
#
# Matter_Plugin_Relay.be - implements the behavior for a Relay (OnOff)
#
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Matter plug-in for core behavior
# dummy declaration for solidification
class Matter_Plugin end
#@ solidify:Matter_Plugin_Relay,weak
class Matter_Plugin_Relay : Matter_Plugin
static var ENDPOINTS = [ 1 ]
static var CLUSTERS = {
0x001D: [0,1,2,3],
0x0003: [],
0x0004: [],
0x0005: [],
0x0006: [0],
0x0008: [],
# 0x0406: []
}
static var TYPES = [ 0x0100 ] # On/Off Light
#############################################################
# Constructor
def init(device)
super(self).init(device)
self.endpoints = self.ENDPOINTS
self.clusters = self.CLUSTERS
end
#############################################################
# read an attribute
#
def read_attribute(msg, ctx)
import string
var TLV = matter.TLV
var cluster = ctx.cluster
var attribute = ctx.attribute
if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ----------
var dtl = TLV.Matter_TLV_array()
var d1 = dtl.add_struct()
d1.add_TLV(0, TLV.U2, self.TYPES[0]) # DeviceType
d1.add_TLV(1, TLV.U2, 1) # Revision
return dtl
elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ----------
var sl = TLV.Matter_TLV_array()
for cl: self.get_cluster_list()
sl.add_TLV(nil, TLV.U4, cl)
end
return sl
elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ----------
var cl = TLV.Matter_TLV_array()
cl.add_TLV(nil, TLV.U2, 0x0006)
return cl
elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]----------
var pl = TLV.Matter_TLV_array()
return pl
end
end
# no match found, return that the attribute is unsupported end
end
#############################################################
# Invoke a command
#
# returns a TLV object if successful, contains the response
# or an `int` to indicate a status
def invoke_request(msg, val, ctx)
# no match found, return that the command is unsupported
end
end
matter.Plugin_core = Matter_Plugin_core

View File

@ -1,5 +1,5 @@
#
# Matter_Plugin_core.be - implements the core features that a Matter device must implemment
# Matter_Plugin_Root.be - implements the core features that a Matter device must implemment
#
# Copyright (C) 2023 Stephan Hadinger & Theo Arends
#
@ -17,30 +17,33 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Matter plug-in for core behavior
# Matter plug-in for root behavior
# dummy declaration for solidification
class Matter_Plugin end
#@ solidify:Matter_Plugin_core,weak
#@ solidify:Matter_Plugin_Root,weak
class Matter_Plugin_core : Matter_Plugin
class Matter_Plugin_Root : Matter_Plugin
static var ENDPOINTS = [ 0 ]
static var CLUSTERS = {
0x001D: [0,1,2,3],
0x0028: [0,1,2,3,4,5,6,7,8,9],
0x002B: [0,1],
0x002C: [0,1,2],
0x0030: [0,1,2,3,4],
0x0031: [3,0xFFFC],
0x0032: [],
0x0033: [0,1,2,8],
0x0034: [],
0x0038: [0,1,7],
0x003E: [0,1,2,3,4,5],
0x003C: [],
0x003F: []
0x001D: [0,1,2,3], # Descriptor Cluster 9.5 p.453
0x001F: [0,2,3,4], # Access Control Cluster, p.461
0x0028: [0,1,2,3,4,5,6,7,8,9,0x12],# Basic Information Cluster cluster 11.1 p.565
0x002A: [0,1,2,3], # OTA Software Update Requestor Cluster Definition 11.19.7 p.762
0x002B: [0,1], # Localization Configuration Cluster 11.3 p.580
0x002C: [0,1,2], # Time Format Localization Cluster 11.4 p.581
0x0030: [0,1,2,3,4], # GeneralCommissioning cluster 11.9 p.627
0x0031: [3,4,0xFFFC], # Network Commissioning Cluster cluster 11.8 p.606
0x0032: [], # Diagnostic Logs Cluster 11.10 p.637
0x0033: [0,1,2,8], # General Diagnostics Cluster 11.11 p.642
0x0034: [], # Software Diagnostics Cluster 11.12 p.654
0x0038: [0,1,7], # Time Synchronization 11.16 p.689
0x003C: [], # Administrator Commissioning Cluster 11.18 p.725
0x003E: [0,1,2,3,4,5], # Node Operational Credentials Cluster 11.17 p.704
0x003F: [] # Group Key Management Cluster 11.2 p.572
}
static var TYPES = [ 0x0016 ] # On/Off Light
#############################################################
# Constructor
@ -62,7 +65,7 @@ class Matter_Plugin_core : Matter_Plugin
if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ==========
if attribute == 0x0000 # ---------- Breadcrumb ----------
return TLV.create_TLV(TLV.U8, msg.session.breadcrumb)
return TLV.create_TLV(TLV.U8, msg.session.__breadcrumb)
elif attribute == 0x0001 # ---------- BasicCommissioningInfo / BasicCommissioningInfo----------
var bci = TLV.Matter_TLV_struct()
bci.add_TLV(0, TLV.U2, 60) # FailSafeExpiryLengthSeconds
@ -211,19 +214,34 @@ class Matter_Plugin_core : Matter_Plugin
return TLV.create_TLV(TLV.U2, 0)
elif attribute == 0x000A # ---------- SoftwareVersionString / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Version'])
elif attribute == 0x0012 # ---------- UniqueID / string 32 max ----------
return TLV.create_TLV(TLV.UTF1, tasmota.wifi().find("mac", ""))
end
# ====================================================================================================
elif cluster == 0x003F # ========== Group Key Management Cluster 11.2 p.572 ==========
# TODO
# ====================================================================================================
elif cluster == 0x002A # ========== OTA Software Update Requestor Cluster Definition 11.19.7 p.762 ==========
if attribute == 0x0000 # ---------- DefaultOTAProviders / list[ProviderLocationStruct] ----------
return TLV.Matter_TLV_array() # empty list for now TODO
elif attribute == 0x0001 # ---------- UpdatePossible / bool ----------
return TLV.create_TLV(TLV.BOOL, 0) # we claim that update is not possible, would require to go to Tasmota UI
elif attribute == 0x0002 # ---------- UpdateState / UpdateStateEnum ----------
return TLV.create_TLV(TLV.U1, 1) # Idle
elif attribute == 0x0003 # ---------- UpdateStateProgress / uint8 ----------
return TLV.create_TLV(TLV.NULL, nil) # null, nothing in process
end
# ====================================================================================================
elif cluster == 0x002B # ========== Localization Configuration Cluster 11.3 p.580 ==========
if attribute == 0x0000 # ---------- ActiveLocale / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.locale())
elif attribute == 0x0001 # ---------- SupportedLocales / list[string] ----------
var locl = TLV.Matter_TLV_list()
var locl = TLV.Matter_TLV_array()
locl.add_TLV(nil, TLV.UTF1, tasmota.locale())
return locl
end
@ -236,7 +254,7 @@ class Matter_Plugin_core : Matter_Plugin
elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ----------
return TLV.create_TLV(TLV.U1, 4) # 4 = Gregorian
elif attribute == 0x0002 # ---------- SupportedCalendarTypes / list[CalendarType] ----------
var callist = TLV.Matter_TLV_list()
var callist = TLV.Matter_TLV_array()
callist.add_TLV(nil, TLV.create_TLV(TLV.U1, 4))
return callist
end
@ -252,6 +270,13 @@ class Matter_Plugin_core : Matter_Plugin
# ====================================================================================================
elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ==========
if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ----------
var dtl = TLV.Matter_TLV_array()
for dt: self.TYPES
var d1 = dtl.add_struct()
d1.add_TLV(0, TLV.U2, dt) # DeviceType
d1.add_TLV(1, TLV.U2, 1) # Revision
end
return dtl
elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ----------
var sl = TLV.Matter_TLV_array()
for cl: self.get_cluster_list()
@ -297,7 +322,7 @@ class Matter_Plugin_core : Matter_Plugin
# 1=DebugText
var ExpiryLengthSeconds = val.findsubval(0, 900)
var Breadcrumb = val.findsubval(1, 0)
session.breadcrumb = Breadcrumb
session.__breadcrumb = Breadcrumb
var afsr = TLV.Matter_TLV_struct()
afsr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK
@ -309,7 +334,7 @@ class Matter_Plugin_core : Matter_Plugin
var NewRegulatoryConfig = val.findsubval(0) # RegulatoryLocationType Enum
var CountryCode = val.findsubval(1, "XX")
var Breadcrumb = val.findsubval(2, 0)
session.breadcrumb = Breadcrumb
session.__breadcrumb = Breadcrumb
# create SetRegulatoryConfigResponse
# ID=1
# 0=ErrorCode (OK=0)
@ -322,7 +347,7 @@ class Matter_Plugin_core : Matter_Plugin
elif command == 0x0004 # ---------- CommissioningComplete p.636 ----------
# no data
session.breadcrumb = 0 # clear breadcrumb
session.__breadcrumb = 0 # clear breadcrumb
session.set_no_expiration()
# create CommissioningCompleteResponse
@ -487,6 +512,85 @@ class Matter_Plugin_core : Matter_Plugin
end
end
#############################################################
# write an attribute
#
def write_attribute(msg, ctx, write_data)
import string
var TLV = matter.TLV
var cluster = ctx.cluster
var attribute = ctx.attribute
# 0x001D no writable attributes
# 0x0032 no attributes
# 0x0033 no writable attributes
# 0x0034 no writable attributes
# 0x0038 no mandatory writable attributes
# 0x003C no writable attributes
# 0x003E no writable attributes
if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ==========
if attribute == 0x0000 # ---------- Breadcrumb ----------
if type(write_data) == 'int' || isinstance(write_data, int64)
msg.session.__breadcrumb = write_data
return true
else
ctx.status = matter.CONSTRAINT_ERROR
return false
end
end
# ====================================================================================================
elif cluster == 0x001F # ========== Access Control Cluster 9.10 p.461 ==========
if attribute == 0x0000 # ACL - list[AccessControlEntryStruct]
return true
end
# ====================================================================================================
elif cluster == 0x0028 # ========== Basic Information Cluster cluster 11.1 p.565 ==========
if attribute == 0x0005 # ---------- NodeLabel / string ----------
# TODO
return true
elif attribute == 0x0006 # ---------- Location / string ----------
# TODO
return true
end
# ====================================================================================================
elif cluster == 0x002A # ========== OTA Software Update Requestor Cluster Definition 11.19.7 p.762 ==========
if attribute == 0x0000 # ---------- DefaultOTAProviders / list[ProviderLocationStruct] ----------
return true # silently ignore
end
# ====================================================================================================
elif cluster == 0x002B # ========== Localization Configuration Cluster 11.3 p.580 ==========
if attribute == 0x0000 # ---------- ActiveLocale / string ----------
ctx.status = matter.CONSTRAINT_ERROR # changing locale is not possible
return false
end
# ====================================================================================================
elif cluster == 0x002C # ========== Time Format Localization Cluster 11.4 p.581 ==========
if attribute == 0x0000 # ---------- HourFormat / HourFormat ----------
# TODO
return true
elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ----------
# TODO
return true
end
# ====================================================================================================
elif cluster == 0x0031 # ========== Network Commissioning Cluster cluster 11.8 p.606 ==========
if attribute == 0x0004 # ---------- InterfaceEnabled / bool ----------
ctx.status = matter.INVALID_ACTION
return false
end
end
end
end
matter.Plugin_core = Matter_Plugin_core
matter.Plugin_Root = Matter_Plugin_Root

View File

@ -47,6 +47,10 @@ class Matter_Session
# counters
var counter_rcv # counter for incoming messages
var counter_snd # counter for outgoing messages
var __exchange_id # exchange id for locally initiated transaction, non-persistent
# keep track of last known IP/Port of the fabric
var __ip
var __port
# non-session counters
var _counter_insecure_rcv # counter for incoming messages
var _counter_insecure_snd # counter for outgoing messages
@ -57,7 +61,7 @@ class Matter_Session
var attestation_challenge # Attestation challenge
var peer_node_id
# breadcrumb
var breadcrumb # breadcrumb attribute for this session
var __breadcrumb # breadcrumb attribute for this session, prefix `__` so that it is not persisted and untouched
# our own private key
var no_private_key # private key of the device certificate (generated at commissioning)
# NOC information
@ -90,6 +94,7 @@ class Matter_Session
#############################################################
def init(store, local_session_id, initiator_session_id)
import crypto
self.__store = store
self.mode = 0
self.local_session_id = local_session_id
@ -98,7 +103,8 @@ class Matter_Session
self.counter_snd = matter.Counter()
self._counter_insecure_rcv = matter.Counter()
self._counter_insecure_snd = matter.Counter()
self.breadcrumb = int64()
self.__breadcrumb = 0
self.__exchange_id = crypto.random(2).get(0,2) # generate a random 16 bits number, then increment with rollover
end
#############################################################

View File

@ -297,6 +297,83 @@ class Matter_TLV
return b
end
#############################################################
# compute the length in bytes of encoded TLV without actually
# allocating buffers (faster and no memory fragmentation)
#
# returns a number of bytes
def encode_len()
var TLV = self.TLV
var len = 0
# special case for bool
# we need to change the type according to the value
if self.typ == TLV.BFALSE || self.typ == TLV.BTRUE
self.typ = bool(self.val) ? TLV.BTRUE : TLV.BFALSE
# try to compress ints
elif self.typ >= TLV.I2 && self.typ <= TLV.I4
var i = int(self.val)
if i <= 127 && i >= -128 self.typ = TLV.I1
elif i <= 32767 && i >= -32768 self.typ = TLV.I2
end
elif self.typ >= TLV.U2 && self.typ <= TLV.U4
var i = int(self.val)
if i <= 255 && i >= 0 self.typ = TLV.U1
elif i <= 65535 && i >= 0 self.typ = TLV.U2
end
elif self.typ >= TLV.B1 && self.typ <= TLV.B8 # encode length as minimum possible
if size(self.val) <= 255
self.typ = TLV.B1
elif size(self.val) <= 65535
self.typ = TLV.B2
else
self.typ = TLV.B4 # B4 is unlikely, B8 is impossible
end
elif self.typ >= TLV.UTF1 && self.typ <= TLV.UTF8
if size(self.val) <= 255
self.typ = TLV.UTF1
elif size(self.val) <= 65535
self.typ = TLV.UTF2
else
self.typ = TLV.UTF4 # UTF4 is unlikely, UTF8 is impossible
end
end
# encode tag and type
len += self._encode_tag_len()
# encode value
if self.typ == TLV.I1 || self.typ == TLV.U1
len += 1
elif self.typ == TLV.I2 || self.typ == TLV.U2
len += 2
elif self.typ == TLV.I4 || self.typ == TLV.U4
len += 4
elif self.typ == TLV.I8 || self.typ == TLV.U8
len += 8
elif self.typ == TLV.BFALSE || self.typ == TLV.BTRUE
# push nothing
elif self.typ == TLV.FLOAT
len += 4
elif self.typ == TLV.DOUBLE
raise "value_error", "Unsupported type TLV.DOUBLE"
elif self.typ == TLV.UTF1
len += 1 + size(self.val)
elif self.typ == TLV.UTF2
len += 2 + size(self.val)
elif self.typ == TLV.B1
len += 1 + size(self.val)
elif self.typ == TLV.B2
len += 2 + size(self.val)
elif self.typ == TLV.NULL
# push nothing
else
raise "value_error", "unsupported type " + str(self.typ)
end
return len
end
#############################################################
# internal_function
# encode Tag+Type as the first bytes
@ -341,6 +418,39 @@ class Matter_TLV
end
end
#############################################################
# internal_function
# compute len of Tag+Type as the first bytes
def _encode_tag_len()
var tag_number = self.tag_number != nil ? self.tag_number : 0
var tag_huge = (tag_number >= 65536) || (tag_number < 0)
var tag_control = 0x00
if self.tag_vendor != nil
# full encoding
if tag_huge
return 9
else
return 7
end
elif self.tag_profile == -1 # Matter Common profile
if tag_huge
return 5
else
return 3
end
elif self.tag_profile != nil
if tag_huge
return 5
else
return 3
end
elif self.tag_sub != nil
return 2
else # anonymous tag
return 1
end
end
#############################################################
# Compare the value index with an element
# returns:
@ -494,16 +604,14 @@ class Matter_TLV
end
#############################################################
# encode TLV
#
# appends to the bytes() object
def _encode_inner(b, is_struct)
# encode to bytes
def encode(b)
if b == nil b = bytes() end
# encode tag and type
self._encode_tag(b)
# sort values
var val_list = self.val.copy()
if is_struct
if self.is_struct
self.sort(val_list)
end
@ -519,9 +627,22 @@ class Matter_TLV
end
#############################################################
# encode to bytes
def encode(b)
return self._encode_inner(b, self.is_struct)
# compute the length in bytes of encoded TLV without actually
# allocating buffers (faster and no memory fragmentation)
#
# returns a number of bytes
def encode_len()
# tag and type
var len = self._encode_tag_len()
# output each one after the other, order doesn't infulence size
var idx = 0
while idx < size(self.val)
len += self.val[idx].encode_len()
idx += 1
end
# add 'end of container'
len += 1
return len
end
#############################################################
@ -760,117 +881,52 @@ matter.TLV = Matter_TLV
# Test
import matter
#load("Matter_TLV.be")
def test_TLV(b, s)
var m = matter.TLV.parse(b)
assert(m.tostring() == s)
assert(m.encode() == b)
assert(m.encode_len() == size(b))
end
var m
m = matter.TLV.parse(bytes("2502054C"))
assert(m.tostring() == "2 = 19461U")
assert(m.encode() == bytes("2502054C"))
test_TLV(bytes("2502054C"), "2 = 19461U")
test_TLV(bytes("0001"), "1")
test_TLV(bytes("08"), "false")
test_TLV(bytes("09"), "true")
m = matter.TLV.parse(bytes("0001"))
assert(m.tostring() == "1")
assert(m.encode() == bytes("0001"))
test_TLV(bytes("00FF"), "-1")
test_TLV(bytes("05FFFF"), "65535U")
m = matter.TLV.parse(bytes("08"))
assert(m.tostring() == "false")
assert(m.encode() == bytes("08"))
m = matter.TLV.parse(bytes("09"))
assert(m.tostring() == "true")
assert(m.encode() == bytes("09"))
m = matter.TLV.parse(bytes("01FFFF"))
assert(m.tostring() == "-1")
assert(m.encode() == bytes("00FF"))
m = matter.TLV.parse(bytes("05FFFF"))
assert(m.tostring() == "65535U")
assert(m.encode() == bytes("05FFFF"))
m = matter.TLV.parse(bytes("0A0000C03F"))
assert(m.tostring() == "1.5")
assert(m.encode() == bytes("0A0000C03F"))
m = matter.TLV.parse(bytes("0C06466f6f626172"))
assert(m.tostring() == '"Foobar"')
assert(m.encode() == bytes("0C06466f6f626172"))
m = matter.TLV.parse(bytes("1006466f6f626172"))
assert(m.tostring() == "466F6F626172")
assert(m.encode() == bytes("1006466f6f626172"))
m = matter.TLV.parse(bytes("e4f1ffeddeedfe55aa2a"))
assert(m.tostring() == "0xFFF1::0xDEED:0xAA55FEED = 42U")
assert(m.encode() == bytes("e4f1ffeddeedfe55aa2a"))
m = matter.TLV.parse(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"))
assert(m.tostring() == "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")
assert(m.encode() == bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"))
test_TLV(bytes("0A0000C03F"), "1.5")
test_TLV(bytes("0C06466f6f626172"), '"Foobar"')
test_TLV(bytes("1006466f6f626172"), "466F6F626172")
test_TLV(bytes("e4f1ffeddeedfe55aa2a"), "0xFFF1::0xDEED:0xAA55FEED = 42U")
test_TLV(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"), "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")
# context specific
m = matter.TLV.parse(bytes("24012a"))
assert(m.tostring() == "1 = 42U")
assert(m.encode() == bytes("24012a"))
m = matter.TLV.parse(bytes("4401002a"))
assert(m.tostring() == "Matter::0x00000001 = 42U")
assert(m.encode() == bytes("4401002a"))
test_TLV(bytes("24012a"), "1 = 42U")
test_TLV(bytes("4401002a"), "Matter::0x00000001 = 42U")
# int64
m = matter.TLV.parse(bytes("030102000000000000"))
assert(m.tostring() == "513")
assert(m.encode() == bytes("030102000000000000"))
m = matter.TLV.parse(bytes("070102000000000000"))
assert(m.tostring() == "513U")
assert(m.encode() == bytes("070102000000000000"))
m = matter.TLV.parse(bytes("03FFFFFFFFFFFFFFFF"))
assert(m.tostring() == "-1")
assert(m.encode() == bytes("03FFFFFFFFFFFFFFFF"))
m = matter.TLV.parse(bytes("07FFFFFFFFFFFFFF7F"))
assert(m.tostring() == "9223372036854775807U")
assert(m.encode() == bytes("07FFFFFFFFFFFFFF7F"))
test_TLV(bytes("030102000000000000"), "513")
test_TLV(bytes("070102000000000000"), "513U")
test_TLV(bytes("03FFFFFFFFFFFFFFFF"), "-1")
test_TLV(bytes("07FFFFFFFFFFFFFF7F"), "9223372036854775807U")
# structure
m = matter.TLV.parse(bytes("1518"))
assert(m.tostring() == "{}")
assert(m.encode() == bytes("1518"))
m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"))
assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}")
assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"))
m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}")
assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
test_TLV(bytes("1518"), "{}")
test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}")
test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}")
# list
m = matter.TLV.parse(bytes("1718"))
assert(m.tostring() == "[[]]")
assert(m.encode() == bytes("1718"))
m = matter.TLV.parse(bytes("17000120002a000200032000ef18"))
assert(m.tostring() == "[[1, 0 = 42, 2, 3, 0 = -17]]")
assert(m.encode() == bytes("17000120002a000200032000ef18"))
test_TLV(bytes("1718"), "[[]]")
test_TLV(bytes("17000120002a000200032000ef18"), "[[1, 0 = 42, 2, 3, 0 = -17]]")
# array
m = matter.TLV.parse(bytes("1618"))
assert(m.tostring() == "[]")
assert(m.encode() == bytes("1618"))
m = matter.TLV.parse(bytes("160000000100020003000418"))
assert(m.tostring() == "[0, 1, 2, 3, 4]")
assert(m.encode() == bytes("160000000100020003000418"))
test_TLV(bytes("1618"), "[]")
test_TLV(bytes("160000000100020003000418"), "[0, 1, 2, 3, 4]")
# mix
m = matter.TLV.parse(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"))
assert(m.tostring() == '[42, -170000, {}, 17.9, "Hello!"]')
assert(m.encode() == bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"))
m = matter.TLV.parse(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"))
assert(m.tostring() == '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}')
assert(m.encode() == bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"))
test_TLV(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"), '[42, -170000, {}, 17.9, "Hello!"]')
test_TLV(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"), '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}')
-#

View File

@ -55,9 +55,9 @@ class Matter_UDPPacket_sent
import string
var ok = udp_socket.send(self.addr ? self.addr : udp_socket.remote_ip, self.port ? self.port : udp_socket.remote_port, self.raw)
if ok
tasmota.log(string.format("MTR: sending packet to '[%s]:%i'", self.addr, self.port), 3)
tasmota.log(string.format("MTR: sending packet to '[%s]:%i'", self.addr, self.port), 4)
else
tasmota.log(string.format("MTR: failed to send packet to '[%s]:%i'", self.addr, self.port), 2)
tasmota.log(string.format("MTR: error sending packet to '[%s]:%i'", self.addr, self.port), 3)
end
end
end
@ -144,7 +144,9 @@ class Matter_UDPServer
packet.send(self.udp_socket) # resend
packet.retries -= 1
if packet.retries <= 0
import string
self.packets_sent.remove(packet.msg_id)
tasmota.log(string.format("MTR: non-acked packet to '[%s]:%i'", packet.addr, packet.port), 3)
else
packet.next_try = tasmota.millis() + packet.RETRY_MS
end
@ -158,7 +160,7 @@ class Matter_UDPServer
if id == nil return end
if self.packets_sent.contains(id)
self.packets_sent.remove(id)
tasmota.log("MTR: removed packet from sending list id=" + str(id), 3)
tasmota.log("MTR: removed packet from sending list id=" + str(id), 4)
end
end

View File

@ -270,7 +270,7 @@ be_local_closure(Matter_Pake1_parse, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[11]) { /* constants */
( &(const bvalue[10]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
@ -278,10 +278,9 @@ be_local_closure(Matter_Pake1_parse, /* name */
/* K4 */ be_nested_str_weak(tasmota),
/* K5 */ be_nested_str_weak(log),
/* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20),
/* K7 */ be_const_int(3),
/* K8 */ be_nested_str_weak(pA),
/* K9 */ be_nested_str_weak(getsubval),
/* K10 */ be_const_int(1),
/* K7 */ be_nested_str_weak(pA),
/* K8 */ be_nested_str_weak(getsubval),
/* K9 */ be_const_int(1),
}),
be_str_weak(parse),
&be_const_str_solidified,
@ -302,12 +301,12 @@ be_local_closure(Matter_Pake1_parse, /* name */
0x5C1C0600, // 000D MOVE R7 R3
0x7C180200, // 000E CALL R6 1
0x001A0C06, // 000F ADD R6 K6 R6
0x581C0007, // 0010 LDCONST R7 K7
0x541E0003, // 0010 LDINT R7 4
0x7C100600, // 0011 CALL R4 3
0x8C100709, // 0012 GETMET R4 R3 K9
0x5818000A, // 0013 LDCONST R6 K10
0x8C100708, // 0012 GETMET R4 R3 K8
0x58180009, // 0013 LDCONST R6 K9
0x7C100400, // 0014 CALL R4 2
0x90021004, // 0015 SETMBR R0 K8 R4
0x90020E04, // 0015 SETMBR R0 K7 R4
0x80040000, // 0016 RET 1 R0
})
)
@ -430,7 +429,7 @@ be_local_closure(Matter_Pake3_parse, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[11]) { /* constants */
( &(const bvalue[10]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
@ -438,10 +437,9 @@ be_local_closure(Matter_Pake3_parse, /* name */
/* K4 */ be_nested_str_weak(tasmota),
/* K5 */ be_nested_str_weak(log),
/* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20),
/* K7 */ be_const_int(3),
/* K8 */ be_nested_str_weak(cA),
/* K9 */ be_nested_str_weak(getsubval),
/* K10 */ be_const_int(1),
/* K7 */ be_nested_str_weak(cA),
/* K8 */ be_nested_str_weak(getsubval),
/* K9 */ be_const_int(1),
}),
be_str_weak(parse),
&be_const_str_solidified,
@ -462,12 +460,12 @@ be_local_closure(Matter_Pake3_parse, /* name */
0x5C1C0600, // 000D MOVE R7 R3
0x7C180200, // 000E CALL R6 1
0x001A0C06, // 000F ADD R6 K6 R6
0x581C0007, // 0010 LDCONST R7 K7
0x541E0003, // 0010 LDINT R7 4
0x7C100600, // 0011 CALL R4 3
0x8C100709, // 0012 GETMET R4 R3 K9
0x5818000A, // 0013 LDCONST R6 K10
0x8C100708, // 0012 GETMET R4 R3 K8
0x58180009, // 0013 LDCONST R6 K9
0x7C100400, // 0014 CALL R4 2
0x90021004, // 0015 SETMBR R0 K8 R4
0x90020E04, // 0015 SETMBR R0 K7 R4
0x80040000, // 0016 RET 1 R0
})
)
@ -521,13 +519,13 @@ be_local_closure(Matter_Sigma1_parse, /* name */
/* K6 */ be_nested_str_weak(tasmota),
/* K7 */ be_nested_str_weak(log),
/* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma1_X20TLV_X3D),
/* K9 */ be_const_int(3),
/* K10 */ be_nested_str_weak(initiatorRandom),
/* K11 */ be_nested_str_weak(getsubval),
/* K12 */ be_const_int(1),
/* K13 */ be_nested_str_weak(initiator_session_id),
/* K14 */ be_const_int(2),
/* K15 */ be_nested_str_weak(destinationId),
/* K9 */ be_nested_str_weak(initiatorRandom),
/* K10 */ be_nested_str_weak(getsubval),
/* K11 */ be_const_int(1),
/* K12 */ be_nested_str_weak(initiator_session_id),
/* K13 */ be_const_int(2),
/* K14 */ be_nested_str_weak(destinationId),
/* K15 */ be_const_int(3),
/* K16 */ be_nested_str_weak(initiatorEphPubKey),
/* K17 */ be_nested_str_weak(findsub),
/* K18 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
@ -556,21 +554,21 @@ be_local_closure(Matter_Sigma1_parse, /* name */
0x5C1C0600, // 0010 MOVE R7 R3
0x7C180200, // 0011 CALL R6 1
0x001A1006, // 0012 ADD R6 K8 R6
0x581C0009, // 0013 LDCONST R7 K9
0x541E0003, // 0013 LDINT R7 4
0x7C100600, // 0014 CALL R4 3
0x8C10070B, // 0015 GETMET R4 R3 K11
0x5818000C, // 0016 LDCONST R6 K12
0x8C10070A, // 0015 GETMET R4 R3 K10
0x5818000B, // 0016 LDCONST R6 K11
0x7C100400, // 0017 CALL R4 2
0x90021404, // 0018 SETMBR R0 K10 R4
0x8C10070B, // 0019 GETMET R4 R3 K11
0x5818000E, // 001A LDCONST R6 K14
0x90021204, // 0018 SETMBR R0 K9 R4
0x8C10070A, // 0019 GETMET R4 R3 K10
0x5818000D, // 001A LDCONST R6 K13
0x7C100400, // 001B CALL R4 2
0x90021A04, // 001C SETMBR R0 K13 R4
0x8C10070B, // 001D GETMET R4 R3 K11
0x58180009, // 001E LDCONST R6 K9
0x90021804, // 001C SETMBR R0 K12 R4
0x8C10070A, // 001D GETMET R4 R3 K10
0x5818000F, // 001E LDCONST R6 K15
0x7C100400, // 001F CALL R4 2
0x90021E04, // 0020 SETMBR R0 K15 R4
0x8C10070B, // 0021 GETMET R4 R3 K11
0x90021C04, // 0020 SETMBR R0 K14 R4
0x8C10070A, // 0021 GETMET R4 R3 K10
0x541A0003, // 0022 LDINT R6 4
0x7C100400, // 0023 CALL R4 2
0x90022004, // 0024 SETMBR R0 K16 R4
@ -581,11 +579,11 @@ be_local_closure(Matter_Sigma1_parse, /* name */
0x20140805, // 0029 NE R5 R4 R5
0x78160007, // 002A JMPF R5 #0033
0x8C140913, // 002B GETMET R5 R4 K19
0x581C000C, // 002C LDCONST R7 K12
0x581C000B, // 002C LDCONST R7 K11
0x7C140400, // 002D CALL R5 2
0x90022405, // 002E SETMBR R0 K18 R5
0x8C140913, // 002F GETMET R5 R4 K19
0x581C000E, // 0030 LDCONST R7 K14
0x581C000D, // 0030 LDCONST R7 K13
0x7C140400, // 0031 CALL R5 2
0x90022805, // 0032 SETMBR R0 K20 R5
0x8C140711, // 0033 GETMET R5 R3 K17
@ -895,7 +893,7 @@ be_local_closure(Matter_Sigma3_parse, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[13]) { /* constants */
( &(const bvalue[12]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
@ -905,10 +903,9 @@ be_local_closure(Matter_Sigma3_parse, /* name */
/* K6 */ be_nested_str_weak(tasmota),
/* K7 */ be_nested_str_weak(log),
/* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20TLV_X3D),
/* K9 */ be_const_int(3),
/* K10 */ be_nested_str_weak(TBEData3Encrypted),
/* K11 */ be_nested_str_weak(getsubval),
/* K12 */ be_const_int(1),
/* K9 */ be_nested_str_weak(TBEData3Encrypted),
/* K10 */ be_nested_str_weak(getsubval),
/* K11 */ be_const_int(1),
}),
be_str_weak(parse),
&be_const_str_solidified,
@ -932,12 +929,12 @@ be_local_closure(Matter_Sigma3_parse, /* name */
0x5C1C0600, // 0010 MOVE R7 R3
0x7C180200, // 0011 CALL R6 1
0x001A1006, // 0012 ADD R6 K8 R6
0x581C0009, // 0013 LDCONST R7 K9
0x541E0003, // 0013 LDINT R7 4
0x7C100600, // 0014 CALL R4 3
0x8C10070B, // 0015 GETMET R4 R3 K11
0x5818000C, // 0016 LDCONST R6 K12
0x8C10070A, // 0015 GETMET R4 R3 K10
0x5818000B, // 0016 LDCONST R6 K11
0x7C100400, // 0017 CALL R4 2
0x90021404, // 0018 SETMBR R0 K10 R4
0x90021204, // 0018 SETMBR R0 K9 R4
0x80040000, // 0019 RET 1 R0
})
)

File diff suppressed because it is too large Load Diff

View File

@ -3026,7 +3026,7 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(max_interval_ceiling),
/* K6 */ be_const_int(2),
/* K7 */ be_nested_str_weak(attribute_requests),
/* K7 */ be_nested_str_weak(attributes_requests),
/* K8 */ be_nested_str_weak(from_TLV_array),
/* K9 */ be_const_int(3),
/* K10 */ be_nested_str_weak(matter),
@ -3041,7 +3041,7 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */
}),
be_str_weak(from_TLV),
&be_const_str_solidified,
( &(const binstruction[54]) { /* code */
( &(const binstruction[58]) { /* code */
0x4C080000, // 0000 LDNIL R2
0x1C080202, // 0001 EQ R2 R1 R2
0x780A0001, // 0002 JMPF R2 #0005
@ -3049,53 +3049,57 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */
0x80040400, // 0004 RET 1 R2
0x8C080301, // 0005 GETMET R2 R1 K1
0x58100002, // 0006 LDCONST R4 K2
0x7C080400, // 0007 CALL R2 2
0x90020002, // 0008 SETMBR R0 K0 R2
0x8C080301, // 0009 GETMET R2 R1 K1
0x58100004, // 000A LDCONST R4 K4
0x7C080400, // 000B CALL R2 2
0x90020602, // 000C SETMBR R0 K3 R2
0x8C080301, // 000D GETMET R2 R1 K1
0x58100006, // 000E LDCONST R4 K6
0x7C080400, // 000F CALL R2 2
0x90020A02, // 0010 SETMBR R0 K5 R2
0x8C080108, // 0011 GETMET R2 R0 K8
0x8C100301, // 0012 GETMET R4 R1 K1
0x58180009, // 0013 LDCONST R6 K9
0x7C100400, // 0014 CALL R4 2
0xB8161400, // 0015 GETNGBL R5 K10
0x88140B0B, // 0016 GETMBR R5 R5 K11
0x7C080600, // 0017 CALL R2 3
0x90020E02, // 0018 SETMBR R0 K7 R2
0x8C080108, // 0019 GETMET R2 R0 K8
0x8C100301, // 001A GETMET R4 R1 K1
0x541A0003, // 001B LDINT R6 4
0x7C100400, // 001C CALL R4 2
0xB8161400, // 001D GETNGBL R5 K10
0x88140B0D, // 001E GETMBR R5 R5 K13
0x7C080600, // 001F CALL R2 3
0x90021802, // 0020 SETMBR R0 K12 R2
0x8C080108, // 0021 GETMET R2 R0 K8
0x8C100301, // 0022 GETMET R4 R1 K1
0x541A0004, // 0023 LDINT R6 5
0x7C100400, // 0024 CALL R4 2
0xB8161400, // 0025 GETNGBL R5 K10
0x88140B0F, // 0026 GETMBR R5 R5 K15
0x7C080600, // 0027 CALL R2 3
0x90021C02, // 0028 SETMBR R0 K14 R2
0x8C080301, // 0029 GETMET R2 R1 K1
0x54120006, // 002A LDINT R4 7
0x7C080400, // 002B CALL R2 2
0x90022002, // 002C SETMBR R0 K16 R2
0x8C080108, // 002D GETMET R2 R0 K8
0x8C100301, // 002E GETMET R4 R1 K1
0x541A0007, // 002F LDINT R6 8
0x7C100400, // 0030 CALL R4 2
0xB8161400, // 0031 GETNGBL R5 K10
0x88140B12, // 0032 GETMBR R5 R5 K18
0x7C080600, // 0033 CALL R2 3
0x90022202, // 0034 SETMBR R0 K17 R2
0x80040000, // 0035 RET 1 R0
0x50140000, // 0007 LDBOOL R5 0 0
0x7C080600, // 0008 CALL R2 3
0x90020002, // 0009 SETMBR R0 K0 R2
0x8C080301, // 000A GETMET R2 R1 K1
0x58100004, // 000B LDCONST R4 K4
0x58140002, // 000C LDCONST R5 K2
0x7C080600, // 000D CALL R2 3
0x90020602, // 000E SETMBR R0 K3 R2
0x8C080301, // 000F GETMET R2 R1 K1
0x58100006, // 0010 LDCONST R4 K6
0x5416003B, // 0011 LDINT R5 60
0x7C080600, // 0012 CALL R2 3
0x90020A02, // 0013 SETMBR R0 K5 R2
0x8C080108, // 0014 GETMET R2 R0 K8
0x8C100301, // 0015 GETMET R4 R1 K1
0x58180009, // 0016 LDCONST R6 K9
0x7C100400, // 0017 CALL R4 2
0xB8161400, // 0018 GETNGBL R5 K10
0x88140B0B, // 0019 GETMBR R5 R5 K11
0x7C080600, // 001A CALL R2 3
0x90020E02, // 001B SETMBR R0 K7 R2
0x8C080108, // 001C GETMET R2 R0 K8
0x8C100301, // 001D GETMET R4 R1 K1
0x541A0003, // 001E LDINT R6 4
0x7C100400, // 001F CALL R4 2
0xB8161400, // 0020 GETNGBL R5 K10
0x88140B0D, // 0021 GETMBR R5 R5 K13
0x7C080600, // 0022 CALL R2 3
0x90021802, // 0023 SETMBR R0 K12 R2
0x8C080108, // 0024 GETMET R2 R0 K8
0x8C100301, // 0025 GETMET R4 R1 K1
0x541A0004, // 0026 LDINT R6 5
0x7C100400, // 0027 CALL R4 2
0xB8161400, // 0028 GETNGBL R5 K10
0x88140B0F, // 0029 GETMBR R5 R5 K15
0x7C080600, // 002A CALL R2 3
0x90021C02, // 002B SETMBR R0 K14 R2
0x8C080301, // 002C GETMET R2 R1 K1
0x54120006, // 002D LDINT R4 7
0x50140000, // 002E LDBOOL R5 0 0
0x7C080600, // 002F CALL R2 3
0x90022002, // 0030 SETMBR R0 K16 R2
0x8C080108, // 0031 GETMET R2 R0 K8
0x8C100301, // 0032 GETMET R4 R1 K1
0x541A0007, // 0033 LDINT R6 8
0x7C100400, // 0034 CALL R4 2
0xB8161400, // 0035 GETNGBL R5 K10
0x88140B12, // 0036 GETMBR R5 R5 K18
0x7C080600, // 0037 CALL R2 3
0x90022202, // 0038 SETMBR R0 K17 R2
0x80040000, // 0039 RET 1 R0
})
)
);
@ -3130,7 +3134,7 @@ be_local_closure(Matter_SubscribeRequestMessage_to_TLV, /* name */
/* K11 */ be_nested_str_weak(max_interval_ceiling),
/* K12 */ be_nested_str_weak(to_TLV_array),
/* K13 */ be_const_int(3),
/* K14 */ be_nested_str_weak(attribute_requests),
/* K14 */ be_nested_str_weak(attributes_requests),
/* K15 */ be_nested_str_weak(event_requests),
/* K16 */ be_nested_str_weak(event_filters),
/* K17 */ be_nested_str_weak(fabric_filtered),
@ -3207,13 +3211,13 @@ be_local_class(Matter_SubscribeRequestMessage,
be_nested_map(10,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(to_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_to_TLV_closure) },
{ be_const_key_weak(event_filters, -1), be_const_var(5) },
{ be_const_key_weak(event_requests, 6), be_const_var(4) },
{ be_const_key_weak(attributes_requests, 7), be_const_var(3) },
{ be_const_key_weak(fabric_filtered, 6), be_const_var(6) },
{ be_const_key_weak(min_interval_floor, -1), be_const_var(1) },
{ be_const_key_weak(data_version_filters, -1), be_const_var(7) },
{ be_const_key_weak(max_interval_ceiling, -1), be_const_var(2) },
{ be_const_key_weak(attribute_requests, 7), be_const_var(3) },
{ be_const_key_weak(fabric_filtered, 3), be_const_var(6) },
{ be_const_key_weak(event_requests, 3), be_const_var(4) },
{ be_const_key_weak(event_filters, -1), be_const_var(5) },
{ be_const_key_weak(from_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_from_TLV_closure) },
{ be_const_key_weak(keep_subscriptions, 0), be_const_var(0) },
})),

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,585 @@
/* Solidification of Matter_IM_Subscription.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_IM_Subscription;
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_IM_Subscription_init, /* name */
be_nested_proto(
12, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[24]) { /* constants */
/* K0 */ be_nested_str_weak(subscription_id),
/* K1 */ be_nested_str_weak(session),
/* K2 */ be_nested_str_weak(min_interval_floor),
/* K3 */ be_const_int(0),
/* K4 */ be_nested_str_weak(min_interval),
/* K5 */ be_nested_str_weak(max_interval_ceiling),
/* K6 */ be_nested_str_weak(max_interval),
/* K7 */ be_nested_str_weak(fabric_filtered),
/* K8 */ be_nested_str_weak(path_list),
/* K9 */ be_nested_str_weak(attributes_requests),
/* K10 */ be_nested_str_weak(matter),
/* K11 */ be_nested_str_weak(Path),
/* K12 */ be_nested_str_weak(endpoint),
/* K13 */ be_nested_str_weak(cluster),
/* K14 */ be_nested_str_weak(attribute),
/* K15 */ be_nested_str_weak(push),
/* K16 */ be_nested_str_weak(stop_iteration),
/* K17 */ be_nested_str_weak(updates),
/* K18 */ be_nested_str_weak(clear_and_arm),
/* K19 */ be_nested_str_weak(tasmota),
/* K20 */ be_nested_str_weak(log),
/* K21 */ be_nested_str_weak(MTR_X3A_X20new_X20subsctiption_X20),
/* K22 */ be_nested_str_weak(inspect),
/* K23 */ be_const_int(2),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[64]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x90020202, // 0001 SETMBR R0 K1 R2
0x88100702, // 0002 GETMBR R4 R3 K2
0x14140903, // 0003 LT R5 R4 K3
0x78160000, // 0004 JMPF R5 #0006
0x58100003, // 0005 LDCONST R4 K3
0x5416003B, // 0006 LDINT R5 60
0x24140805, // 0007 GT R5 R4 R5
0x78160000, // 0008 JMPF R5 #000A
0x5412003B, // 0009 LDINT R4 60
0x90020804, // 000A SETMBR R0 K4 R4
0x88140705, // 000B GETMBR R5 R3 K5
0x541A003B, // 000C LDINT R6 60
0x14180A06, // 000D LT R6 R5 R6
0x781A0000, // 000E JMPF R6 #0010
0x5416003B, // 000F LDINT R5 60
0x541A0E0F, // 0010 LDINT R6 3600
0x24180A06, // 0011 GT R6 R5 R6
0x781A0000, // 0012 JMPF R6 #0014
0x54160E0F, // 0013 LDINT R5 3600
0x90020C05, // 0014 SETMBR R0 K6 R5
0x88180707, // 0015 GETMBR R6 R3 K7
0x90020E06, // 0016 SETMBR R0 K7 R6
0x60180012, // 0017 GETGBL R6 G18
0x7C180000, // 0018 CALL R6 0
0x90021006, // 0019 SETMBR R0 K8 R6
0x60180010, // 001A GETGBL R6 G16
0x881C0709, // 001B GETMBR R7 R3 K9
0x7C180200, // 001C CALL R6 1
0xA802000F, // 001D EXBLK 0 #002E
0x5C1C0C00, // 001E MOVE R7 R6
0x7C1C0000, // 001F CALL R7 0
0xB8221400, // 0020 GETNGBL R8 K10
0x8C20110B, // 0021 GETMET R8 R8 K11
0x7C200200, // 0022 CALL R8 1
0x88240F0C, // 0023 GETMBR R9 R7 K12
0x90221809, // 0024 SETMBR R8 K12 R9
0x88240F0D, // 0025 GETMBR R9 R7 K13
0x90221A09, // 0026 SETMBR R8 K13 R9
0x88240F0E, // 0027 GETMBR R9 R7 K14
0x90221C09, // 0028 SETMBR R8 K14 R9
0x88240108, // 0029 GETMBR R9 R0 K8
0x8C24130F, // 002A GETMET R9 R9 K15
0x5C2C1000, // 002B MOVE R11 R8
0x7C240400, // 002C CALL R9 2
0x7001FFEF, // 002D JMP #001E
0x58180010, // 002E LDCONST R6 K16
0xAC180200, // 002F CATCH R6 1 0
0xB0080000, // 0030 RAISE 2 R0 R0
0x60180012, // 0031 GETGBL R6 G18
0x7C180000, // 0032 CALL R6 0
0x90022206, // 0033 SETMBR R0 K17 R6
0x8C180112, // 0034 GETMET R6 R0 K18
0x7C180200, // 0035 CALL R6 1
0xB81A2600, // 0036 GETNGBL R6 K19
0x8C180D14, // 0037 GETMET R6 R6 K20
0xB8221400, // 0038 GETNGBL R8 K10
0x8C201116, // 0039 GETMET R8 R8 K22
0x5C280000, // 003A MOVE R10 R0
0x7C200400, // 003B CALL R8 2
0x00222A08, // 003C ADD R8 K21 R8
0x58240017, // 003D LDCONST R9 K23
0x7C180600, // 003E CALL R6 3
0x80000000, // 003F RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: attribute_updated
********************************************************************/
be_local_closure(Matter_IM_Subscription_attribute_updated, /* name */
be_nested_proto(
8, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 8]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(path_list),
/* K2 */ be_nested_str_weak(endpoint),
/* K3 */ be_nested_str_weak(cluster),
/* K4 */ be_nested_str_weak(attribute),
/* K5 */ be_nested_str_weak(updates),
/* K6 */ be_nested_str_weak(push),
/* K7 */ be_const_int(1),
}),
be_str_weak(attribute_updated),
&be_const_str_solidified,
( &(const binstruction[39]) { /* code */
0x580C0000, // 0000 LDCONST R3 K0
0x6010000C, // 0001 GETGBL R4 G12
0x88140101, // 0002 GETMBR R5 R0 K1
0x7C100200, // 0003 CALL R4 1
0x14100604, // 0004 LT R4 R3 R4
0x7812001F, // 0005 JMPF R4 #0026
0x88100101, // 0006 GETMBR R4 R0 K1
0x94100803, // 0007 GETIDX R4 R4 R3
0x88140902, // 0008 GETMBR R5 R4 K2
0x4C180000, // 0009 LDNIL R6
0x1C140A06, // 000A EQ R5 R5 R6
0x74160003, // 000B JMPT R5 #0010
0x88140902, // 000C GETMBR R5 R4 K2
0x88180302, // 000D GETMBR R6 R1 K2
0x1C140A06, // 000E EQ R5 R5 R6
0x78160013, // 000F JMPF R5 #0024
0x88140903, // 0010 GETMBR R5 R4 K3
0x4C180000, // 0011 LDNIL R6
0x1C140A06, // 0012 EQ R5 R5 R6
0x74160003, // 0013 JMPT R5 #0018
0x88140903, // 0014 GETMBR R5 R4 K3
0x88180303, // 0015 GETMBR R6 R1 K3
0x1C140A06, // 0016 EQ R5 R5 R6
0x7816000B, // 0017 JMPF R5 #0024
0x88140904, // 0018 GETMBR R5 R4 K4
0x4C180000, // 0019 LDNIL R6
0x1C140A06, // 001A EQ R5 R5 R6
0x74160003, // 001B JMPT R5 #0020
0x88140904, // 001C GETMBR R5 R4 K4
0x88180304, // 001D GETMBR R6 R1 K4
0x1C140A06, // 001E EQ R5 R5 R6
0x78160003, // 001F JMPF R5 #0024
0x88140105, // 0020 GETMBR R5 R0 K5
0x8C140B06, // 0021 GETMET R5 R5 K6
0x5C1C0200, // 0022 MOVE R7 R1
0x7C140400, // 0023 CALL R5 2
0x000C0707, // 0024 ADD R3 R3 K7
0x7001FFDA, // 0025 JMP #0001
0x80000000, // 0026 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: clear_and_arm
********************************************************************/
be_local_closure(Matter_IM_Subscription_clear_and_arm, /* name */
be_nested_proto(
4, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 7]) { /* constants */
/* K0 */ be_nested_str_weak(updates),
/* K1 */ be_nested_str_weak(clear),
/* K2 */ be_nested_str_weak(expiration),
/* K3 */ be_nested_str_weak(tasmota),
/* K4 */ be_nested_str_weak(millis),
/* K5 */ be_nested_str_weak(max_interval),
/* K6 */ be_nested_str_weak(MAX_INTERVAL_MARGIN),
}),
be_str_weak(clear_and_arm),
&be_const_str_solidified,
( &(const binstruction[14]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x8C040301, // 0001 GETMET R1 R1 K1
0x7C040200, // 0002 CALL R1 1
0xB8060600, // 0003 GETNGBL R1 K3
0x8C040304, // 0004 GETMET R1 R1 K4
0x7C040200, // 0005 CALL R1 1
0x88080105, // 0006 GETMBR R2 R0 K5
0x880C0106, // 0007 GETMBR R3 R0 K6
0x04080403, // 0008 SUB R2 R2 R3
0x540E03E7, // 0009 LDINT R3 1000
0x08080403, // 000A MUL R2 R2 R3
0x00040202, // 000B ADD R1 R1 R2
0x90020401, // 000C SETMBR R0 K2 R1
0x80000000, // 000D RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_IM_Subscription
********************************************************************/
be_local_class(Matter_IM_Subscription,
8,
NULL,
be_nested_map(12,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(expiration, -1), be_const_var(6) },
{ be_const_key_weak(updates, 9), be_const_var(7) },
{ be_const_key_weak(fabric_filtered, -1), be_const_var(5) },
{ be_const_key_weak(max_interval, 10), be_const_var(4) },
{ be_const_key_weak(session, -1), be_const_var(1) },
{ be_const_key_weak(min_interval, -1), be_const_var(3) },
{ be_const_key_weak(MAX_INTERVAL_MARGIN, -1), be_const_int(10) },
{ be_const_key_weak(attribute_updated, 4), be_const_closure(Matter_IM_Subscription_attribute_updated_closure) },
{ be_const_key_weak(subscription_id, -1), be_const_var(0) },
{ be_const_key_weak(clear_and_arm, -1), be_const_closure(Matter_IM_Subscription_clear_and_arm_closure) },
{ be_const_key_weak(path_list, 11), be_const_var(2) },
{ be_const_key_weak(init, -1), be_const_closure(Matter_IM_Subscription_init_closure) },
})),
be_str_weak(Matter_IM_Subscription)
);
/*******************************************************************/
void be_load_Matter_IM_Subscription_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_IM_Subscription);
be_setglobal(vm, "Matter_IM_Subscription");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_IM_Subscription_Shop;
/********************************************************************
** Solidified function: new_subscription
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_new_subscription, /* name */
be_nested_proto(
10, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[10]) { /* constants */
/* K0 */ be_nested_str_weak(crypto),
/* K1 */ be_nested_str_weak(random),
/* K2 */ be_const_int(2),
/* K3 */ be_nested_str_weak(get),
/* K4 */ be_const_int(0),
/* K5 */ be_nested_str_weak(get_by_id),
/* K6 */ be_nested_str_weak(matter),
/* K7 */ be_nested_str_weak(IM_Subscription),
/* K8 */ be_nested_str_weak(subs),
/* K9 */ be_nested_str_weak(push),
}),
be_str_weak(new_subscription),
&be_const_str_solidified,
( &(const binstruction[32]) { /* code */
0xA40E0000, // 0000 IMPORT R3 K0
0x8C100701, // 0001 GETMET R4 R3 K1
0x58180002, // 0002 LDCONST R6 K2
0x7C100400, // 0003 CALL R4 2
0x8C100903, // 0004 GETMET R4 R4 K3
0x58180004, // 0005 LDCONST R6 K4
0x581C0002, // 0006 LDCONST R7 K2
0x7C100600, // 0007 CALL R4 3
0x8C140105, // 0008 GETMET R5 R0 K5
0x5C1C0800, // 0009 MOVE R7 R4
0x7C140400, // 000A CALL R5 2
0x78160008, // 000B JMPF R5 #0015
0x8C140701, // 000C GETMET R5 R3 K1
0x581C0002, // 000D LDCONST R7 K2
0x7C140400, // 000E CALL R5 2
0x8C140B03, // 000F GETMET R5 R5 K3
0x581C0004, // 0010 LDCONST R7 K4
0x58200002, // 0011 LDCONST R8 K2
0x7C140600, // 0012 CALL R5 3
0x5C100A00, // 0013 MOVE R4 R5
0x7001FFF2, // 0014 JMP #0008
0xB8160C00, // 0015 GETNGBL R5 K6
0x8C140B07, // 0016 GETMET R5 R5 K7
0x5C1C0800, // 0017 MOVE R7 R4
0x5C200200, // 0018 MOVE R8 R1
0x5C240400, // 0019 MOVE R9 R2
0x7C140800, // 001A CALL R5 4
0x88180108, // 001B GETMBR R6 R0 K8
0x8C180D09, // 001C GETMET R6 R6 K9
0x5C200A00, // 001D MOVE R8 R5
0x7C180400, // 001E CALL R6 2
0x80040A00, // 001F RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: every_second
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_every_second, /* name */
be_nested_proto(
6, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 9]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(subs),
/* K2 */ be_nested_str_weak(tasmota),
/* K3 */ be_nested_str_weak(time_reached),
/* K4 */ be_nested_str_weak(expiration),
/* K5 */ be_nested_str_weak(im),
/* K6 */ be_nested_str_weak(send_subscribe_update),
/* K7 */ be_nested_str_weak(clear_and_arm),
/* K8 */ be_const_int(1),
}),
be_str_weak(every_second),
&be_const_str_solidified,
( &(const binstruction[22]) { /* code */
0x58040000, // 0000 LDCONST R1 K0
0x6008000C, // 0001 GETGBL R2 G12
0x880C0101, // 0002 GETMBR R3 R0 K1
0x7C080200, // 0003 CALL R2 1
0x14080202, // 0004 LT R2 R1 R2
0x780A000E, // 0005 JMPF R2 #0015
0x88080101, // 0006 GETMBR R2 R0 K1
0x94080401, // 0007 GETIDX R2 R2 R1
0xB80E0400, // 0008 GETNGBL R3 K2
0x8C0C0703, // 0009 GETMET R3 R3 K3
0x88140504, // 000A GETMBR R5 R2 K4
0x7C0C0400, // 000B CALL R3 2
0x780E0005, // 000C JMPF R3 #0013
0x880C0105, // 000D GETMBR R3 R0 K5
0x8C0C0706, // 000E GETMET R3 R3 K6
0x5C140400, // 000F MOVE R5 R2
0x7C0C0400, // 0010 CALL R3 2
0x8C0C0507, // 0011 GETMET R3 R2 K7
0x7C0C0200, // 0012 CALL R3 1
0x00040308, // 0013 ADD R1 R1 K8
0x7001FFEB, // 0014 JMP #0001
0x80000000, // 0015 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_init, /* name */
be_nested_proto(
3, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str_weak(im),
/* K1 */ be_nested_str_weak(subs),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x60080012, // 0001 GETGBL R2 G18
0x7C080000, // 0002 CALL R2 0
0x90020202, // 0003 SETMBR R0 K1 R2
0x80000000, // 0004 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: remove_by_session
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_remove_by_session, /* name */
be_nested_proto(
6, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 5]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(subs),
/* K2 */ be_nested_str_weak(session),
/* K3 */ be_nested_str_weak(remove),
/* K4 */ be_const_int(1),
}),
be_str_weak(remove_by_session),
&be_const_str_solidified,
( &(const binstruction[19]) { /* code */
0x58080000, // 0000 LDCONST R2 K0
0x600C000C, // 0001 GETGBL R3 G12
0x88100101, // 0002 GETMBR R4 R0 K1
0x7C0C0200, // 0003 CALL R3 1
0x140C0403, // 0004 LT R3 R2 R3
0x780E000B, // 0005 JMPF R3 #0012
0x880C0101, // 0006 GETMBR R3 R0 K1
0x940C0602, // 0007 GETIDX R3 R3 R2
0x880C0702, // 0008 GETMBR R3 R3 K2
0x1C0C0601, // 0009 EQ R3 R3 R1
0x780E0004, // 000A JMPF R3 #0010
0x880C0101, // 000B GETMBR R3 R0 K1
0x8C0C0703, // 000C GETMET R3 R3 K3
0x5C140400, // 000D MOVE R5 R2
0x7C0C0400, // 000E CALL R3 2
0x70020000, // 000F JMP #0011
0x00080504, // 0010 ADD R2 R2 K4
0x7001FFEE, // 0011 JMP #0001
0x80000000, // 0012 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: get_by_id
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_get_by_id, /* name */
be_nested_proto(
5, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 4]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(subs),
/* K2 */ be_nested_str_weak(subscription_id),
/* K3 */ be_const_int(1),
}),
be_str_weak(get_by_id),
&be_const_str_solidified,
( &(const binstruction[17]) { /* code */
0x58080000, // 0000 LDCONST R2 K0
0x600C000C, // 0001 GETGBL R3 G12
0x88100101, // 0002 GETMBR R4 R0 K1
0x7C0C0200, // 0003 CALL R3 1
0x140C0403, // 0004 LT R3 R2 R3
0x780E0009, // 0005 JMPF R3 #0010
0x880C0101, // 0006 GETMBR R3 R0 K1
0x940C0602, // 0007 GETIDX R3 R3 R2
0x880C0702, // 0008 GETMBR R3 R3 K2
0x1C0C0601, // 0009 EQ R3 R3 R1
0x780E0002, // 000A JMPF R3 #000E
0x880C0101, // 000B GETMBR R3 R0 K1
0x940C0602, // 000C GETIDX R3 R3 R2
0x80040600, // 000D RET 1 R3
0x00080503, // 000E ADD R2 R2 K3
0x7001FFF0, // 000F JMP #0001
0x80000000, // 0010 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: attribute_updated
********************************************************************/
be_local_closure(Matter_IM_Subscription_Shop_attribute_updated, /* name */
be_nested_proto(
8, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 4]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(subs),
/* K2 */ be_nested_str_weak(attribute_updated),
/* K3 */ be_const_int(1),
}),
be_str_weak(attribute_updated),
&be_const_str_solidified,
( &(const binstruction[15]) { /* code */
0x580C0000, // 0000 LDCONST R3 K0
0x6010000C, // 0001 GETGBL R4 G12
0x88140101, // 0002 GETMBR R5 R0 K1
0x7C100200, // 0003 CALL R4 1
0x14100604, // 0004 LT R4 R3 R4
0x78120007, // 0005 JMPF R4 #000E
0x88100101, // 0006 GETMBR R4 R0 K1
0x94100803, // 0007 GETIDX R4 R4 R3
0x8C100902, // 0008 GETMET R4 R4 K2
0x5C180200, // 0009 MOVE R6 R1
0x5C1C0400, // 000A MOVE R7 R2
0x7C100600, // 000B CALL R4 3
0x000C0703, // 000C ADD R3 R3 K3
0x7001FFF2, // 000D JMP #0001
0x80000000, // 000E RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_IM_Subscription_Shop
********************************************************************/
be_local_class(Matter_IM_Subscription_Shop,
2,
NULL,
be_nested_map(8,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_IM_Subscription_Shop_attribute_updated_closure) },
{ be_const_key_weak(every_second, -1), be_const_closure(Matter_IM_Subscription_Shop_every_second_closure) },
{ be_const_key_weak(subs, -1), be_const_var(0) },
{ be_const_key_weak(init, 5), be_const_closure(Matter_IM_Subscription_Shop_init_closure) },
{ be_const_key_weak(remove_by_session, -1), be_const_closure(Matter_IM_Subscription_Shop_remove_by_session_closure) },
{ be_const_key_weak(im, 6), be_const_var(1) },
{ be_const_key_weak(get_by_id, -1), be_const_closure(Matter_IM_Subscription_Shop_get_by_id_closure) },
{ be_const_key_weak(new_subscription, 0), be_const_closure(Matter_IM_Subscription_Shop_new_subscription_closure) },
})),
be_str_weak(Matter_IM_Subscription_Shop)
);
/*******************************************************************/
void be_load_Matter_IM_Subscription_Shop_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_IM_Subscription_Shop);
be_setglobal(vm, "Matter_IM_Subscription_Shop");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -45,7 +45,7 @@ be_local_closure(Matter_MessageHandler_send_response, /* name */
********************************************************************/
be_local_closure(Matter_MessageHandler_msg_received, /* name */
be_nested_proto(
17, /* nstack */
18, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
@ -53,7 +53,7 @@ be_local_closure(Matter_MessageHandler_msg_received, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[59]) { /* constants */
( &(const bvalue[69]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(log),
@ -72,342 +72,374 @@ be_local_closure(Matter_MessageHandler_msg_received, /* name */
/* K15 */ be_nested_str_weak(MTR_X3A_X20find_X20session_X20by_X20source_node_id_X20_X3D_X20),
/* K16 */ be_nested_str_weak(session_id_X20_X3D_X20),
/* K17 */ be_const_int(3),
/* K18 */ be_nested_str_weak(session),
/* K19 */ be_nested_str_weak(counter_rcv),
/* K20 */ be_nested_str_weak(validate),
/* K21 */ be_nested_str_weak(message_counter),
/* K22 */ be_nested_str_weak(format),
/* K23 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20unencrypted_X20message_X20_X3D_X20_X25i_X20ref_X20_X3D_X20_X25i),
/* K24 */ be_nested_str_weak(val),
/* K25 */ be_nested_str_weak(decode_payload),
/* K26 */ be_nested_str_weak(packet_ack),
/* K27 */ be_nested_str_weak(ack_message_counter),
/* K28 */ be_nested_str_weak(opcode),
/* K29 */ be_nested_str_weak(get_opcode_name),
/* K30 */ be_nested_str_weak(0x_X2502X),
/* K31 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_X20_X20_X20_X20_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i),
/* K32 */ be_const_int(2),
/* K33 */ be_nested_str_weak(commissioning),
/* K34 */ be_nested_str_weak(process_incoming),
/* K35 */ be_nested_str_weak(MTR_X3A_X20decode_X20header_X3A_X20local_session_id_X3D_X25i_X20message_counter_X3D_X25i),
/* K36 */ be_nested_str_weak(get_session_by_local_session_id),
/* K37 */ be_nested_str_weak(MTR_X3A_X20unknown_X20local_session_id_X20),
/* K38 */ be_nested_str_weak(MTR_X3A_X20frame_X3D),
/* K39 */ be_nested_str_weak(inspect),
/* K40 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20encrypted_X20message_X20_X3D_X20),
/* K41 */ be_nested_str_weak(_X20counter_X3D),
/* K42 */ be_nested_str_weak(decrypt),
/* K43 */ be_nested_str_weak(raw),
/* K44 */ be_nested_str_weak(payload_idx),
/* K45 */ be_const_int(1),
/* K46 */ be_nested_str_weak(MTR_X3A_X20idx_X3D_X25i_X20clear_X3D_X25s),
/* K47 */ be_nested_str_weak(MTR_X3A_X20decrypted_X20message_X3A_X20protocol_id_X3A),
/* K48 */ be_nested_str_weak(protocol_id),
/* K49 */ be_nested_str_weak(_X20opcode_X3D),
/* K50 */ be_nested_str_weak(_X20exchange_id),
/* K51 */ be_nested_str_weak(exchange_id),
/* K52 */ be_nested_str_weak(MTR_X3A_X20PROTOCOL_ID_SECURE_CHANNEL_X20),
/* K53 */ be_nested_str_weak(im),
/* K54 */ be_nested_str_weak(MTR_X3A_X20ignoring_X20unhandled_X20protocol_id_X3A),
/* K55 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20exception_X3A_X20),
/* K56 */ be_nested_str_weak(_X3B),
/* K57 */ be_nested_str_weak(debug),
/* K58 */ be_nested_str_weak(traceback),
/* K18 */ be_nested_str_weak(__ip),
/* K19 */ be_nested_str_weak(__port),
/* K20 */ be_nested_str_weak(session),
/* K21 */ be_nested_str_weak(counter_rcv),
/* K22 */ be_nested_str_weak(validate),
/* K23 */ be_nested_str_weak(message_counter),
/* K24 */ be_nested_str_weak(format),
/* K25 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20unencrypted_X20message_X20_X3D_X20_X25i_X20ref_X20_X3D_X20_X25i),
/* K26 */ be_nested_str_weak(val),
/* K27 */ be_nested_str_weak(decode_payload),
/* K28 */ be_nested_str_weak(packet_ack),
/* K29 */ be_nested_str_weak(ack_message_counter),
/* K30 */ be_nested_str_weak(opcode),
/* K31 */ be_nested_str_weak(get_opcode_name),
/* K32 */ be_nested_str_weak(0x_X2502X),
/* K33 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i),
/* K34 */ be_const_int(2),
/* K35 */ be_nested_str_weak(commissioning),
/* K36 */ be_nested_str_weak(process_incoming),
/* K37 */ be_nested_str_weak(MTR_X3A_X20decode_X20header_X3A_X20local_session_id_X3D_X25i_X20message_counter_X3D_X25i),
/* K38 */ be_nested_str_weak(get_session_by_local_session_id),
/* K39 */ be_nested_str_weak(MTR_X3A_X20unknown_X20local_session_id_X20),
/* K40 */ be_nested_str_weak(MTR_X3A_X20frame_X3D),
/* K41 */ be_nested_str_weak(inspect),
/* K42 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20encrypted_X20message_X20_X3D_X20),
/* K43 */ be_nested_str_weak(_X20counter_X3D),
/* K44 */ be_nested_str_weak(decrypt),
/* K45 */ be_nested_str_weak(raw),
/* K46 */ be_nested_str_weak(payload_idx),
/* K47 */ be_const_int(1),
/* K48 */ be_nested_str_weak(MTR_X3A_X20idx_X3D_X25i_X20clear_X3D_X25s),
/* K49 */ be_nested_str_weak(MTR_X3A_X20decrypted_X20message_X3A_X20protocol_id_X3A),
/* K50 */ be_nested_str_weak(protocol_id),
/* K51 */ be_nested_str_weak(_X20opcode_X3D),
/* K52 */ be_nested_str_weak(_X20exchange_id_X3D),
/* K53 */ be_nested_str_weak(exchange_id),
/* K54 */ be_nested_str_weak(MTR_X3A_X20PROTOCOL_ID_SECURE_CHANNEL_X20),
/* K55 */ be_nested_str_weak(im),
/* K56 */ be_nested_str_weak(send_enqueued),
/* K57 */ be_nested_str_weak(x_flag_r),
/* K58 */ be_nested_str_weak(build_standalone_ack),
/* K59 */ be_nested_str_weak(encode),
/* K60 */ be_nested_str_weak(encrypt),
/* K61 */ be_nested_str_weak(send_response),
/* K62 */ be_nested_str_weak(remote_ip),
/* K63 */ be_nested_str_weak(remote_port),
/* K64 */ be_nested_str_weak(MTR_X3A_X20ignoring_X20unhandled_X20protocol_id_X3A),
/* K65 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20exception_X3A_X20),
/* K66 */ be_nested_str_weak(_X3B),
/* K67 */ be_nested_str_weak(debug),
/* K68 */ be_nested_str_weak(traceback),
}),
be_str_weak(msg_received),
&be_const_str_solidified,
( &(const binstruction[291]) { /* code */
( &(const binstruction[313]) { /* code */
0xA4120000, // 0000 IMPORT R4 K0
0xA802010A, // 0001 EXBLK 0 #010D
0xB8160200, // 0002 GETNGBL R5 K1
0x8C140B02, // 0003 GETMET R5 R5 K2
0x8C1C0304, // 0004 GETMET R7 R1 K4
0x7C1C0200, // 0005 CALL R7 1
0x001E0607, // 0006 ADD R7 K3 R7
0x54220003, // 0007 LDINT R8 4
0x7C140600, // 0008 CALL R5 3
0xB8160A00, // 0009 GETNGBL R5 K5
0x8C140B06, // 000A GETMET R5 R5 K6
0x5C1C0000, // 000B MOVE R7 R0
0x5C200200, // 000C MOVE R8 R1
0x5C240400, // 000D MOVE R9 R2
0x5C280600, // 000E MOVE R10 R3
0x7C140A00, // 000F CALL R5 5
0x8C180B07, // 0010 GETMET R6 R5 K7
0x7C180200, // 0011 CALL R6 1
0x5C1C0C00, // 0012 MOVE R7 R6
0x741E0002, // 0013 JMPT R7 #0017
0x501C0000, // 0014 LDBOOL R7 0 0
0xA8040001, // 0015 EXBLK 1 1
0x80040E00, // 0016 RET 1 R7
0x881C0B08, // 0017 GETMBR R7 R5 K8
0x1C1C0F09, // 0018 EQ R7 R7 K9
0x781E0057, // 0019 JMPF R7 #0072
0x881C0B0A, // 001A GETMBR R7 R5 K10
0x1C1C0F09, // 001B EQ R7 R7 K9
0x781E0054, // 001C JMPF R7 #0072
0x881C010B, // 001D GETMBR R7 R0 K11
0x881C0F0C, // 001E GETMBR R7 R7 K12
0x8C1C0F0D, // 001F GETMET R7 R7 K13
0x88240B0E, // 0020 GETMBR R9 R5 K14
0x542A0059, // 0021 LDINT R10 90
0x7C1C0600, // 0022 CALL R7 3
0xB8220200, // 0023 GETNGBL R8 K1
0x8C201102, // 0024 GETMET R8 R8 K2
0x60280008, // 0025 GETGBL R10 G8
0x882C0B0E, // 0026 GETMBR R11 R5 K14
0x7C280200, // 0027 CALL R10 1
0x002A1E0A, // 0028 ADD R10 K15 R10
0x00281510, // 0029 ADD R10 R10 K16
0x602C0008, // 002A GETGBL R11 G8
0x88300F08, // 002B GETMBR R12 R7 K8
0x7C2C0200, // 002C CALL R11 1
0x0028140B, // 002D ADD R10 R10 R11
0x582C0011, // 002E LDCONST R11 K17
0x7C200600, // 002F CALL R8 3
0x90162407, // 0030 SETMBR R5 K18 R7
0x88200113, // 0031 GETMBR R8 R0 K19
0x8C201114, // 0032 GETMET R8 R8 K20
0x88280B15, // 0033 GETMBR R10 R5 K21
0x502C0000, // 0034 LDBOOL R11 0 0
0x7C200600, // 0035 CALL R8 3
0x7422000D, // 0036 JMPT R8 #0045
0xB8220200, // 0037 GETNGBL R8 K1
0x8C201102, // 0038 GETMET R8 R8 K2
0x8C280916, // 0039 GETMET R10 R4 K22
0x58300017, // 003A LDCONST R12 K23
0x88340B15, // 003B GETMBR R13 R5 K21
0x88380113, // 003C GETMBR R14 R0 K19
0x8C381D18, // 003D GETMET R14 R14 K24
0x7C380200, // 003E CALL R14 1
0x7C280800, // 003F CALL R10 4
0x582C0011, // 0040 LDCONST R11 K17
0x7C200600, // 0041 CALL R8 3
0x50200000, // 0042 LDBOOL R8 0 0
0xA8040001, // 0043 EXBLK 1 1
0x80041000, // 0044 RET 1 R8
0x8C200B19, // 0045 GETMET R8 R5 K25
0x7C200200, // 0046 CALL R8 1
0x74220002, // 0047 JMPT R8 #004B
0x50200000, // 0048 LDBOOL R8 0 0
0xA8040001, // 0049 EXBLK 1 1
0x80041000, // 004A RET 1 R8
0x8820010B, // 004B GETMBR R8 R0 K11
0x8C20111A, // 004C GETMET R8 R8 K26
0x88280B1B, // 004D GETMBR R10 R5 K27
0x7C200400, // 004E CALL R8 2
0x88200B1C, // 004F GETMBR R8 R5 K28
0x5426000F, // 0050 LDINT R9 16
0x20201009, // 0051 NE R8 R8 R9
0x78220014, // 0052 JMPF R8 #0068
0xB8220A00, // 0053 GETNGBL R8 K5
0x8C20111D, // 0054 GETMET R8 R8 K29
0x88280B1C, // 0055 GETMBR R10 R5 K28
0x7C200400, // 0056 CALL R8 2
0x5C241000, // 0057 MOVE R9 R8
0x74260004, // 0058 JMPT R9 #005E
0x8C240916, // 0059 GETMET R9 R4 K22
0x582C001E, // 005A LDCONST R11 K30
0x88300B1C, // 005B GETMBR R12 R5 K28
0x7C240600, // 005C CALL R9 3
0x5C201200, // 005D MOVE R8 R9
0xB8260200, // 005E GETNGBL R9 K1
0x8C241302, // 005F GETMET R9 R9 K2
0x8C2C0916, // 0060 GETMET R11 R4 K22
0x5834001F, // 0061 LDCONST R13 K31
0x5C381000, // 0062 MOVE R14 R8
0x5C3C0400, // 0063 MOVE R15 R2
0x5C400600, // 0064 MOVE R16 R3
0x7C2C0A00, // 0065 CALL R11 5
0x58300020, // 0066 LDCONST R12 K32
0x7C240600, // 0067 CALL R9 3
0x88200121, // 0068 GETMBR R8 R0 K33
0x8C201122, // 0069 GETMET R8 R8 K34
0x5C280A00, // 006A MOVE R10 R5
0x5C2C0400, // 006B MOVE R11 R2
0x5C300600, // 006C MOVE R12 R3
0x7C200800, // 006D CALL R8 4
0x50200200, // 006E LDBOOL R8 1 0
0xA8040001, // 006F EXBLK 1 1
0x80041000, // 0070 RET 1 R8
0x70020095, // 0071 JMP #0108
0xB81E0200, // 0072 GETNGBL R7 K1
0x8C1C0F02, // 0073 GETMET R7 R7 K2
0x8C240916, // 0074 GETMET R9 R4 K22
0x582C0023, // 0075 LDCONST R11 K35
0x88300B08, // 0076 GETMBR R12 R5 K8
0x88340B15, // 0077 GETMBR R13 R5 K21
0x7C240800, // 0078 CALL R9 4
0x58280011, // 0079 LDCONST R10 K17
0x7C1C0600, // 007A CALL R7 3
0x881C010B, // 007B GETMBR R7 R0 K11
0x881C0F0C, // 007C GETMBR R7 R7 K12
0x8C1C0F24, // 007D GETMET R7 R7 K36
0x88240B08, // 007E GETMBR R9 R5 K8
0x7C1C0400, // 007F CALL R7 2
0x4C200000, // 0080 LDNIL R8
0x1C200E08, // 0081 EQ R8 R7 R8
0x78220013, // 0082 JMPF R8 #0097
0xB8220200, // 0083 GETNGBL R8 K1
0x8C201102, // 0084 GETMET R8 R8 K2
0x60280008, // 0085 GETGBL R10 G8
0x882C0B08, // 0086 GETMBR R11 R5 K8
0x7C280200, // 0087 CALL R10 1
0x002A4A0A, // 0088 ADD R10 K37 R10
0x582C0011, // 0089 LDCONST R11 K17
0x7C200600, // 008A CALL R8 3
0xB8220200, // 008B GETNGBL R8 K1
0x8C201102, // 008C GETMET R8 R8 K2
0xB82A0A00, // 008D GETNGBL R10 K5
0x8C281527, // 008E GETMET R10 R10 K39
0x5C300A00, // 008F MOVE R12 R5
0x7C280400, // 0090 CALL R10 2
0x002A4C0A, // 0091 ADD R10 K38 R10
0x582C0011, // 0092 LDCONST R11 K17
0x7C200600, // 0093 CALL R8 3
0x50200000, // 0094 LDBOOL R8 0 0
0xA8040001, // 0095 EXBLK 1 1
0x80041000, // 0096 RET 1 R8
0x90162407, // 0097 SETMBR R5 K18 R7
0x88200F13, // 0098 GETMBR R8 R7 K19
0x8C201114, // 0099 GETMET R8 R8 K20
0x88280B15, // 009A GETMBR R10 R5 K21
0x502C0200, // 009B LDBOOL R11 1 0
0x7C200600, // 009C CALL R8 3
0x74220011, // 009D JMPT R8 #00B0
0xB8220200, // 009E GETNGBL R8 K1
0x8C201102, // 009F GETMET R8 R8 K2
0x60280008, // 00A0 GETGBL R10 G8
0x882C0B15, // 00A1 GETMBR R11 R5 K21
0x7C280200, // 00A2 CALL R10 1
0x002A500A, // 00A3 ADD R10 K40 R10
0x00281529, // 00A4 ADD R10 R10 K41
0x602C0008, // 00A5 GETGBL R11 G8
0x88300F13, // 00A6 GETMBR R12 R7 K19
0x8C301918, // 00A7 GETMET R12 R12 K24
0x7C300200, // 00A8 CALL R12 1
0x7C2C0200, // 00A9 CALL R11 1
0x0028140B, // 00AA ADD R10 R10 R11
0x582C0011, // 00AB LDCONST R11 K17
0x7C200600, // 00AC CALL R8 3
0x50200000, // 00AD LDBOOL R8 0 0
0xA8040001, // 00AE EXBLK 1 1
0x80041000, // 00AF RET 1 R8
0x8C200B2A, // 00B0 GETMET R8 R5 K42
0x7C200200, // 00B1 CALL R8 1
0x5C241000, // 00B2 MOVE R9 R8
0x74260002, // 00B3 JMPT R9 #00B7
0x50240000, // 00B4 LDBOOL R9 0 0
0xA8040001, // 00B5 EXBLK 1 1
0x80041200, // 00B6 RET 1 R9
0x88240B2C, // 00B7 GETMBR R9 R5 K44
0x0424132D, // 00B8 SUB R9 R9 K45
0x40261209, // 00B9 CONNECT R9 K9 R9
0x88280B2B, // 00BA GETMBR R10 R5 K43
0x94241409, // 00BB GETIDX R9 R10 R9
0x90165609, // 00BC SETMBR R5 K43 R9
0x88240B2B, // 00BD GETMBR R9 R5 K43
0x40241208, // 00BE CONNECT R9 R9 R8
0xB8260200, // 00BF GETNGBL R9 K1
0x8C241302, // 00C0 GETMET R9 R9 K2
0x8C2C0916, // 00C1 GETMET R11 R4 K22
0x5834002E, // 00C2 LDCONST R13 K46
0x88380B2C, // 00C3 GETMBR R14 R5 K44
0x883C0B2B, // 00C4 GETMBR R15 R5 K43
0x8C3C1F04, // 00C5 GETMET R15 R15 K4
0x7C3C0200, // 00C6 CALL R15 1
0x7C2C0800, // 00C7 CALL R11 4
0x58300011, // 00C8 LDCONST R12 K17
0x7C240600, // 00C9 CALL R9 3
0x8C240B19, // 00CA GETMET R9 R5 K25
0x7C240200, // 00CB CALL R9 1
0xB8260200, // 00CC GETNGBL R9 K1
0x8C241302, // 00CD GETMET R9 R9 K2
0x602C0008, // 00CE GETGBL R11 G8
0x88300B30, // 00CF GETMBR R12 R5 K48
0x7C2C0200, // 00D0 CALL R11 1
0x002E5E0B, // 00D1 ADD R11 K47 R11
0x002C1731, // 00D2 ADD R11 R11 K49
0x60300008, // 00D3 GETGBL R12 G8
0x88340B1C, // 00D4 GETMBR R13 R5 K28
0x7C300200, // 00D5 CALL R12 1
0x002C160C, // 00D6 ADD R11 R11 R12
0x002C1732, // 00D7 ADD R11 R11 K50
0x60300008, // 00D8 GETGBL R12 G8
0x88340B33, // 00D9 GETMBR R13 R5 K51
0x7C300200, // 00DA CALL R12 1
0x002C160C, // 00DB ADD R11 R11 R12
0x58300011, // 00DC LDCONST R12 K17
0x7C240600, // 00DD CALL R9 3
0x8824010B, // 00DE GETMBR R9 R0 K11
0x8C24131A, // 00DF GETMET R9 R9 K26
0x882C0B1B, // 00E0 GETMBR R11 R5 K27
0x7C240400, // 00E1 CALL R9 2
0x88240B30, // 00E2 GETMBR R9 R5 K48
0x1C281309, // 00E3 EQ R10 R9 K9
0x782A000C, // 00E4 JMPF R10 #00F2
0xB82A0200, // 00E5 GETNGBL R10 K1
0x8C281502, // 00E6 GETMET R10 R10 K2
0xB8320A00, // 00E7 GETNGBL R12 K5
0x8C301927, // 00E8 GETMET R12 R12 K39
0x5C380A00, // 00E9 MOVE R14 R5
0x7C300400, // 00EA CALL R12 2
0x0032680C, // 00EB ADD R12 K52 R12
0x58340011, // 00EC LDCONST R13 K17
0x7C280600, // 00ED CALL R10 3
0x50280200, // 00EE LDBOOL R10 1 0
0xA8040001, // 00EF EXBLK 1 1
0x80041400, // 00F0 RET 1 R10
0x70020015, // 00F1 JMP #0108
0x1C28132D, // 00F2 EQ R10 R9 K45
0x782A0008, // 00F3 JMPF R10 #00FD
0x88280135, // 00F4 GETMBR R10 R0 K53
0x8C281522, // 00F5 GETMET R10 R10 K34
0x5C300A00, // 00F6 MOVE R12 R5
0x5C340400, // 00F7 MOVE R13 R2
0x5C380600, // 00F8 MOVE R14 R3
0x7C280800, // 00F9 CALL R10 4
0xA8040001, // 00FA EXBLK 1 1
0x80041400, // 00FB RET 1 R10
0x7002000A, // 00FC JMP #0108
0xB82A0200, // 00FD GETNGBL R10 K1
0x8C281502, // 00FE GETMET R10 R10 K2
0x60300008, // 00FF GETGBL R12 G8
0x5C341200, // 0100 MOVE R13 R9
0x7C300200, // 0101 CALL R12 1
0x00326C0C, // 0102 ADD R12 K54 R12
0x58340011, // 0103 LDCONST R13 K17
0x7C280600, // 0104 CALL R10 3
0x50280000, // 0105 LDBOOL R10 0 0
0xA8040001, // 0106 EXBLK 1 1
0x80041400, // 0107 RET 1 R10
0x501C0200, // 0108 LDBOOL R7 1 0
0xA8040001, // 0109 EXBLK 1 1
0x80040E00, // 010A RET 1 R7
0xA8040001, // 010B EXBLK 1 1
0x70020014, // 010C JMP #0122
0xAC140002, // 010D CATCH R5 0 2
0x70020011, // 010E JMP #0121
0xB81E0200, // 010F GETNGBL R7 K1
0x8C1C0F02, // 0110 GETMET R7 R7 K2
0x60240008, // 0111 GETGBL R9 G8
0x5C280A00, // 0112 MOVE R10 R5
0x7C240200, // 0113 CALL R9 1
0x00266E09, // 0114 ADD R9 K55 R9
0x00241338, // 0115 ADD R9 R9 K56
0x60280008, // 0116 GETGBL R10 G8
0x5C2C0C00, // 0117 MOVE R11 R6
0x7C280200, // 0118 CALL R10 1
0x0024120A, // 0119 ADD R9 R9 R10
0x7C1C0400, // 011A CALL R7 2
0xA41E7200, // 011B IMPORT R7 K57
0x8C200F3A, // 011C GETMET R8 R7 K58
0x7C200200, // 011D CALL R8 1
0x50200000, // 011E LDBOOL R8 0 0
0x80041000, // 011F RET 1 R8
0x70020000, // 0120 JMP #0122
0xB0080000, // 0121 RAISE 2 R0 R0
0x80000000, // 0122 RET 0
0x50140000, // 0001 LDBOOL R5 0 0
0xA802011F, // 0002 EXBLK 0 #0123
0xB81A0200, // 0003 GETNGBL R6 K1
0x8C180D02, // 0004 GETMET R6 R6 K2
0x8C200304, // 0005 GETMET R8 R1 K4
0x7C200200, // 0006 CALL R8 1
0x00220608, // 0007 ADD R8 K3 R8
0x54260003, // 0008 LDINT R9 4
0x7C180600, // 0009 CALL R6 3
0xB81A0A00, // 000A GETNGBL R6 K5
0x8C180D06, // 000B GETMET R6 R6 K6
0x5C200000, // 000C MOVE R8 R0
0x5C240200, // 000D MOVE R9 R1
0x5C280400, // 000E MOVE R10 R2
0x5C2C0600, // 000F MOVE R11 R3
0x7C180A00, // 0010 CALL R6 5
0x8C1C0D07, // 0011 GETMET R7 R6 K7
0x7C1C0200, // 0012 CALL R7 1
0x5C200E00, // 0013 MOVE R8 R7
0x74220002, // 0014 JMPT R8 #0018
0x50200000, // 0015 LDBOOL R8 0 0
0xA8040001, // 0016 EXBLK 1 1
0x80041000, // 0017 RET 1 R8
0x88200D08, // 0018 GETMBR R8 R6 K8
0x1C201109, // 0019 EQ R8 R8 K9
0x7822005B, // 001A JMPF R8 #0077
0x88200D0A, // 001B GETMBR R8 R6 K10
0x1C201109, // 001C EQ R8 R8 K9
0x78220058, // 001D JMPF R8 #0077
0x8820010B, // 001E GETMBR R8 R0 K11
0x8820110C, // 001F GETMBR R8 R8 K12
0x8C20110D, // 0020 GETMET R8 R8 K13
0x88280D0E, // 0021 GETMBR R10 R6 K14
0x542E0059, // 0022 LDINT R11 90
0x7C200600, // 0023 CALL R8 3
0xB8260200, // 0024 GETNGBL R9 K1
0x8C241302, // 0025 GETMET R9 R9 K2
0x602C0008, // 0026 GETGBL R11 G8
0x88300D0E, // 0027 GETMBR R12 R6 K14
0x7C2C0200, // 0028 CALL R11 1
0x002E1E0B, // 0029 ADD R11 K15 R11
0x002C1710, // 002A ADD R11 R11 K16
0x60300008, // 002B GETGBL R12 G8
0x88341108, // 002C GETMBR R13 R8 K8
0x7C300200, // 002D CALL R12 1
0x002C160C, // 002E ADD R11 R11 R12
0x58300011, // 002F LDCONST R12 K17
0x7C240600, // 0030 CALL R9 3
0x780A0000, // 0031 JMPF R2 #0033
0x90222402, // 0032 SETMBR R8 K18 R2
0x780E0000, // 0033 JMPF R3 #0035
0x90222603, // 0034 SETMBR R8 K19 R3
0x901A2808, // 0035 SETMBR R6 K20 R8
0x88240115, // 0036 GETMBR R9 R0 K21
0x8C241316, // 0037 GETMET R9 R9 K22
0x882C0D17, // 0038 GETMBR R11 R6 K23
0x50300000, // 0039 LDBOOL R12 0 0
0x7C240600, // 003A CALL R9 3
0x7426000D, // 003B JMPT R9 #004A
0xB8260200, // 003C GETNGBL R9 K1
0x8C241302, // 003D GETMET R9 R9 K2
0x8C2C0918, // 003E GETMET R11 R4 K24
0x58340019, // 003F LDCONST R13 K25
0x88380D17, // 0040 GETMBR R14 R6 K23
0x883C0115, // 0041 GETMBR R15 R0 K21
0x8C3C1F1A, // 0042 GETMET R15 R15 K26
0x7C3C0200, // 0043 CALL R15 1
0x7C2C0800, // 0044 CALL R11 4
0x58300011, // 0045 LDCONST R12 K17
0x7C240600, // 0046 CALL R9 3
0x50240000, // 0047 LDBOOL R9 0 0
0xA8040001, // 0048 EXBLK 1 1
0x80041200, // 0049 RET 1 R9
0x8C240D1B, // 004A GETMET R9 R6 K27
0x7C240200, // 004B CALL R9 1
0x74260002, // 004C JMPT R9 #0050
0x50240000, // 004D LDBOOL R9 0 0
0xA8040001, // 004E EXBLK 1 1
0x80041200, // 004F RET 1 R9
0x8824010B, // 0050 GETMBR R9 R0 K11
0x8C24131C, // 0051 GETMET R9 R9 K28
0x882C0D1D, // 0052 GETMBR R11 R6 K29
0x7C240400, // 0053 CALL R9 2
0x88240D1E, // 0054 GETMBR R9 R6 K30
0x542A000F, // 0055 LDINT R10 16
0x2024120A, // 0056 NE R9 R9 R10
0x78260014, // 0057 JMPF R9 #006D
0xB8260A00, // 0058 GETNGBL R9 K5
0x8C24131F, // 0059 GETMET R9 R9 K31
0x882C0D1E, // 005A GETMBR R11 R6 K30
0x7C240400, // 005B CALL R9 2
0x5C281200, // 005C MOVE R10 R9
0x742A0004, // 005D JMPT R10 #0063
0x8C280918, // 005E GETMET R10 R4 K24
0x58300020, // 005F LDCONST R12 K32
0x88340D1E, // 0060 GETMBR R13 R6 K30
0x7C280600, // 0061 CALL R10 3
0x5C241400, // 0062 MOVE R9 R10
0xB82A0200, // 0063 GETNGBL R10 K1
0x8C281502, // 0064 GETMET R10 R10 K2
0x8C300918, // 0065 GETMET R12 R4 K24
0x58380021, // 0066 LDCONST R14 K33
0x5C3C1200, // 0067 MOVE R15 R9
0x5C400400, // 0068 MOVE R16 R2
0x5C440600, // 0069 MOVE R17 R3
0x7C300A00, // 006A CALL R12 5
0x58340022, // 006B LDCONST R13 K34
0x7C280600, // 006C CALL R10 3
0x88240123, // 006D GETMBR R9 R0 K35
0x8C241324, // 006E GETMET R9 R9 K36
0x5C2C0C00, // 006F MOVE R11 R6
0x5C300400, // 0070 MOVE R12 R2
0x5C340600, // 0071 MOVE R13 R3
0x7C240800, // 0072 CALL R9 4
0x50240200, // 0073 LDBOOL R9 1 0
0xA8040001, // 0074 EXBLK 1 1
0x80041200, // 0075 RET 1 R9
0x700200A7, // 0076 JMP #011F
0xB8220200, // 0077 GETNGBL R8 K1
0x8C201102, // 0078 GETMET R8 R8 K2
0x8C280918, // 0079 GETMET R10 R4 K24
0x58300025, // 007A LDCONST R12 K37
0x88340D08, // 007B GETMBR R13 R6 K8
0x88380D17, // 007C GETMBR R14 R6 K23
0x7C280800, // 007D CALL R10 4
0x582C0011, // 007E LDCONST R11 K17
0x7C200600, // 007F CALL R8 3
0x8820010B, // 0080 GETMBR R8 R0 K11
0x8820110C, // 0081 GETMBR R8 R8 K12
0x8C201126, // 0082 GETMET R8 R8 K38
0x88280D08, // 0083 GETMBR R10 R6 K8
0x7C200400, // 0084 CALL R8 2
0x4C240000, // 0085 LDNIL R9
0x1C241009, // 0086 EQ R9 R8 R9
0x78260013, // 0087 JMPF R9 #009C
0xB8260200, // 0088 GETNGBL R9 K1
0x8C241302, // 0089 GETMET R9 R9 K2
0x602C0008, // 008A GETGBL R11 G8
0x88300D08, // 008B GETMBR R12 R6 K8
0x7C2C0200, // 008C CALL R11 1
0x002E4E0B, // 008D ADD R11 K39 R11
0x58300011, // 008E LDCONST R12 K17
0x7C240600, // 008F CALL R9 3
0xB8260200, // 0090 GETNGBL R9 K1
0x8C241302, // 0091 GETMET R9 R9 K2
0xB82E0A00, // 0092 GETNGBL R11 K5
0x8C2C1729, // 0093 GETMET R11 R11 K41
0x5C340C00, // 0094 MOVE R13 R6
0x7C2C0400, // 0095 CALL R11 2
0x002E500B, // 0096 ADD R11 K40 R11
0x58300011, // 0097 LDCONST R12 K17
0x7C240600, // 0098 CALL R9 3
0x50240000, // 0099 LDBOOL R9 0 0
0xA8040001, // 009A EXBLK 1 1
0x80041200, // 009B RET 1 R9
0x780A0000, // 009C JMPF R2 #009E
0x90222402, // 009D SETMBR R8 K18 R2
0x780E0000, // 009E JMPF R3 #00A0
0x90222603, // 009F SETMBR R8 K19 R3
0x901A2808, // 00A0 SETMBR R6 K20 R8
0x88241115, // 00A1 GETMBR R9 R8 K21
0x8C241316, // 00A2 GETMET R9 R9 K22
0x882C0D17, // 00A3 GETMBR R11 R6 K23
0x50300200, // 00A4 LDBOOL R12 1 0
0x7C240600, // 00A5 CALL R9 3
0x74260011, // 00A6 JMPT R9 #00B9
0xB8260200, // 00A7 GETNGBL R9 K1
0x8C241302, // 00A8 GETMET R9 R9 K2
0x602C0008, // 00A9 GETGBL R11 G8
0x88300D17, // 00AA GETMBR R12 R6 K23
0x7C2C0200, // 00AB CALL R11 1
0x002E540B, // 00AC ADD R11 K42 R11
0x002C172B, // 00AD ADD R11 R11 K43
0x60300008, // 00AE GETGBL R12 G8
0x88341115, // 00AF GETMBR R13 R8 K21
0x8C341B1A, // 00B0 GETMET R13 R13 K26
0x7C340200, // 00B1 CALL R13 1
0x7C300200, // 00B2 CALL R12 1
0x002C160C, // 00B3 ADD R11 R11 R12
0x58300011, // 00B4 LDCONST R12 K17
0x7C240600, // 00B5 CALL R9 3
0x50240000, // 00B6 LDBOOL R9 0 0
0xA8040001, // 00B7 EXBLK 1 1
0x80041200, // 00B8 RET 1 R9
0x8C240D2C, // 00B9 GETMET R9 R6 K44
0x7C240200, // 00BA CALL R9 1
0x5C281200, // 00BB MOVE R10 R9
0x742A0002, // 00BC JMPT R10 #00C0
0x50280000, // 00BD LDBOOL R10 0 0
0xA8040001, // 00BE EXBLK 1 1
0x80041400, // 00BF RET 1 R10
0x88280D2E, // 00C0 GETMBR R10 R6 K46
0x0428152F, // 00C1 SUB R10 R10 K47
0x402A120A, // 00C2 CONNECT R10 K9 R10
0x882C0D2D, // 00C3 GETMBR R11 R6 K45
0x9428160A, // 00C4 GETIDX R10 R11 R10
0x901A5A0A, // 00C5 SETMBR R6 K45 R10
0x88280D2D, // 00C6 GETMBR R10 R6 K45
0x40281409, // 00C7 CONNECT R10 R10 R9
0xB82A0200, // 00C8 GETNGBL R10 K1
0x8C281502, // 00C9 GETMET R10 R10 K2
0x8C300918, // 00CA GETMET R12 R4 K24
0x58380030, // 00CB LDCONST R14 K48
0x883C0D2E, // 00CC GETMBR R15 R6 K46
0x88400D2D, // 00CD GETMBR R16 R6 K45
0x8C402104, // 00CE GETMET R16 R16 K4
0x7C400200, // 00CF CALL R16 1
0x7C300800, // 00D0 CALL R12 4
0x58340011, // 00D1 LDCONST R13 K17
0x7C280600, // 00D2 CALL R10 3
0x8C280D1B, // 00D3 GETMET R10 R6 K27
0x7C280200, // 00D4 CALL R10 1
0xB82A0200, // 00D5 GETNGBL R10 K1
0x8C281502, // 00D6 GETMET R10 R10 K2
0x60300008, // 00D7 GETGBL R12 G8
0x88340D32, // 00D8 GETMBR R13 R6 K50
0x7C300200, // 00D9 CALL R12 1
0x0032620C, // 00DA ADD R12 K49 R12
0x00301933, // 00DB ADD R12 R12 K51
0x60340008, // 00DC GETGBL R13 G8
0x88380D1E, // 00DD GETMBR R14 R6 K30
0x7C340200, // 00DE CALL R13 1
0x0030180D, // 00DF ADD R12 R12 R13
0x00301934, // 00E0 ADD R12 R12 K52
0x60340008, // 00E1 GETGBL R13 G8
0x88380D35, // 00E2 GETMBR R14 R6 K53
0x7C340200, // 00E3 CALL R13 1
0x0030180D, // 00E4 ADD R12 R12 R13
0x58340011, // 00E5 LDCONST R13 K17
0x7C280600, // 00E6 CALL R10 3
0x8828010B, // 00E7 GETMBR R10 R0 K11
0x8C28151C, // 00E8 GETMET R10 R10 K28
0x88300D1D, // 00E9 GETMBR R12 R6 K29
0x7C280400, // 00EA CALL R10 2
0x88280D32, // 00EB GETMBR R10 R6 K50
0x1C2C1509, // 00EC EQ R11 R10 K9
0x782E000A, // 00ED JMPF R11 #00F9
0xB82E0200, // 00EE GETNGBL R11 K1
0x8C2C1702, // 00EF GETMET R11 R11 K2
0xB8360A00, // 00F0 GETNGBL R13 K5
0x8C341B29, // 00F1 GETMET R13 R13 K41
0x5C3C0C00, // 00F2 MOVE R15 R6
0x7C340400, // 00F3 CALL R13 2
0x00366C0D, // 00F4 ADD R13 K54 R13
0x58380011, // 00F5 LDCONST R14 K17
0x7C2C0600, // 00F6 CALL R11 3
0x50140200, // 00F7 LDBOOL R5 1 0
0x70020025, // 00F8 JMP #011F
0x1C2C152F, // 00F9 EQ R11 R10 K47
0x782E001B, // 00FA JMPF R11 #0117
0x882C0137, // 00FB GETMBR R11 R0 K55
0x8C2C1724, // 00FC GETMET R11 R11 K36
0x5C340C00, // 00FD MOVE R13 R6
0x5C380400, // 00FE MOVE R14 R2
0x5C3C0600, // 00FF MOVE R15 R3
0x7C2C0800, // 0100 CALL R11 4
0x5C141600, // 0101 MOVE R5 R11
0x78160004, // 0102 JMPF R5 #0108
0x882C0137, // 0103 GETMBR R11 R0 K55
0x8C2C1738, // 0104 GETMET R11 R11 K56
0x5C340000, // 0105 MOVE R13 R0
0x7C2C0400, // 0106 CALL R11 2
0x7002000D, // 0107 JMP #0116
0x882C0D39, // 0108 GETMBR R11 R6 K57
0x782E000B, // 0109 JMPF R11 #0116
0x8C2C0D3A, // 010A GETMET R11 R6 K58
0x7C2C0200, // 010B CALL R11 1
0x8C30173B, // 010C GETMET R12 R11 K59
0x7C300200, // 010D CALL R12 1
0x8C30173C, // 010E GETMET R12 R11 K60
0x7C300200, // 010F CALL R12 1
0x8C30013D, // 0110 GETMET R12 R0 K61
0x8838172D, // 0111 GETMBR R14 R11 K45
0x883C173E, // 0112 GETMBR R15 R11 K62
0x8840173F, // 0113 GETMBR R16 R11 K63
0x88441717, // 0114 GETMBR R17 R11 K23
0x7C300A00, // 0115 CALL R12 5
0x70020007, // 0116 JMP #011F
0xB82E0200, // 0117 GETNGBL R11 K1
0x8C2C1702, // 0118 GETMET R11 R11 K2
0x60340008, // 0119 GETGBL R13 G8
0x5C381400, // 011A MOVE R14 R10
0x7C340200, // 011B CALL R13 1
0x0036800D, // 011C ADD R13 K64 R13
0x58380011, // 011D LDCONST R14 K17
0x7C2C0600, // 011E CALL R11 3
0xA8040001, // 011F EXBLK 1 1
0x80040A00, // 0120 RET 1 R5
0xA8040001, // 0121 EXBLK 1 1
0x70020014, // 0122 JMP #0138
0xAC180002, // 0123 CATCH R6 0 2
0x70020011, // 0124 JMP #0137
0xB8220200, // 0125 GETNGBL R8 K1
0x8C201102, // 0126 GETMET R8 R8 K2
0x60280008, // 0127 GETGBL R10 G8
0x5C2C0C00, // 0128 MOVE R11 R6
0x7C280200, // 0129 CALL R10 1
0x002A820A, // 012A ADD R10 K65 R10
0x00281542, // 012B ADD R10 R10 K66
0x602C0008, // 012C GETGBL R11 G8
0x5C300E00, // 012D MOVE R12 R7
0x7C2C0200, // 012E CALL R11 1
0x0028140B, // 012F ADD R10 R10 R11
0x7C200400, // 0130 CALL R8 2
0xA4228600, // 0131 IMPORT R8 K67
0x8C241144, // 0132 GETMET R9 R8 K68
0x7C240200, // 0133 CALL R9 1
0x50240000, // 0134 LDBOOL R9 0 0
0x80041200, // 0135 RET 1 R9
0x70020000, // 0136 JMP #0138
0xB0080000, // 0137 RAISE 2 R0 R0
0x80000000, // 0138 RET 0
})
)
);
@ -476,7 +508,7 @@ be_local_closure(Matter_MessageHandler_add_session, /* name */
********************************************************************/
be_local_closure(Matter_MessageHandler_init, /* name */
be_nested_proto(
6, /* nstack */
5, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
@ -496,7 +528,7 @@ be_local_closure(Matter_MessageHandler_init, /* name */
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[17]) { /* code */
( &(const binstruction[16]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0xB80A0400, // 0001 GETNGBL R2 K2
0x8C080503, // 0002 GETMET R2 R2 K3
@ -505,15 +537,14 @@ be_local_closure(Matter_MessageHandler_init, /* name */
0x90020202, // 0005 SETMBR R0 K1 R2
0xB80A0400, // 0006 GETNGBL R2 K2
0x8C080505, // 0007 GETMET R2 R2 K5
0x5C100000, // 0008 MOVE R4 R0
0x5C140200, // 0009 MOVE R5 R1
0x7C080600, // 000A CALL R2 3
0x90020802, // 000B SETMBR R0 K4 R2
0xB80A0400, // 000C GETNGBL R2 K2
0x8C080507, // 000D GETMET R2 R2 K7
0x7C080200, // 000E CALL R2 1
0x90020C02, // 000F SETMBR R0 K6 R2
0x80000000, // 0010 RET 0
0x5C100200, // 0008 MOVE R4 R1
0x7C080400, // 0009 CALL R2 2
0x90020802, // 000A SETMBR R0 K4 R2
0xB80A0400, // 000B GETNGBL R2 K2
0x8C080507, // 000C GETMET R2 R2 K7
0x7C080200, // 000D CALL R2 1
0x90020C02, // 000E SETMBR R0 K6 R2
0x80000000, // 000F RET 0
})
)
);

View File

@ -321,8 +321,8 @@ be_local_closure(Matter_Plugin_get_endpoints, /* name */
********************************************************************/
be_local_closure(Matter_Plugin_write_attribute, /* name */
be_nested_proto(
6, /* nstack */
5, /* argc */
5, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
@ -333,8 +333,8 @@ be_local_closure(Matter_Plugin_write_attribute, /* name */
be_str_weak(write_attribute),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
0x4C100000, // 0000 LDNIL R4
0x80040800, // 0001 RET 1 R4
})
)
);

View File

@ -0,0 +1,389 @@
/* Solidification of Matter_Plugin_OnOff.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_Plugin_OnOff;
/********************************************************************
** Solidified function: invoke_request
********************************************************************/
be_local_closure(Matter_Plugin_OnOff_invoke_request, /* name */
be_nested_proto(
14, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[13]) { /* constants */
/* K0 */ be_nested_str_weak(matter),
/* K1 */ be_nested_str_weak(TLV),
/* K2 */ be_nested_str_weak(cluster),
/* K3 */ be_nested_str_weak(command),
/* K4 */ be_nested_str_weak(session),
/* K5 */ be_const_int(3),
/* K6 */ be_const_int(0),
/* K7 */ be_const_int(1),
/* K8 */ be_nested_str_weak(Matter_TLV_struct),
/* K9 */ be_nested_str_weak(add_TLV),
/* K10 */ be_nested_str_weak(U2),
/* K11 */ be_nested_str_weak(onoff),
/* K12 */ be_const_int(2),
}),
be_str_weak(invoke_request),
&be_const_str_solidified,
( &(const binstruction[69]) { /* code */
0xB8120000, // 0000 GETNGBL R4 K0
0x88100901, // 0001 GETMBR R4 R4 K1
0x88140702, // 0002 GETMBR R5 R3 K2
0x88180703, // 0003 GETMBR R6 R3 K3
0x881C0304, // 0004 GETMBR R7 R1 K4
0x1C200B05, // 0005 EQ R8 R5 K5
0x78220016, // 0006 JMPF R8 #001E
0x1C200D06, // 0007 EQ R8 R6 K6
0x78220002, // 0008 JMPF R8 #000C
0x50200200, // 0009 LDBOOL R8 1 0
0x80041000, // 000A RET 1 R8
0x70020010, // 000B JMP #001D
0x1C200D07, // 000C EQ R8 R6 K7
0x78220009, // 000D JMPF R8 #0018
0x8C200908, // 000E GETMET R8 R4 K8
0x7C200200, // 000F CALL R8 1
0x8C241109, // 0010 GETMET R9 R8 K9
0x582C0006, // 0011 LDCONST R11 K6
0x8830090A, // 0012 GETMBR R12 R4 K10
0x58340006, // 0013 LDCONST R13 K6
0x7C240800, // 0014 CALL R9 4
0x900E0706, // 0015 SETMBR R3 K3 K6
0x80041000, // 0016 RET 1 R8
0x70020004, // 0017 JMP #001D
0x5422003F, // 0018 LDINT R8 64
0x1C200C08, // 0019 EQ R8 R6 R8
0x78220001, // 001A JMPF R8 #001D
0x50200200, // 001B LDBOOL R8 1 0
0x80041000, // 001C RET 1 R8
0x70020025, // 001D JMP #0044
0x54220003, // 001E LDINT R8 4
0x1C200A08, // 001F EQ R8 R5 R8
0x78220002, // 0020 JMPF R8 #0024
0x50200200, // 0021 LDBOOL R8 1 0
0x80041000, // 0022 RET 1 R8
0x7002001F, // 0023 JMP #0044
0x54220004, // 0024 LDINT R8 5
0x1C200A08, // 0025 EQ R8 R5 R8
0x78220002, // 0026 JMPF R8 #002A
0x50200200, // 0027 LDBOOL R8 1 0
0x80041000, // 0028 RET 1 R8
0x70020019, // 0029 JMP #0044
0x54220005, // 002A LDINT R8 6
0x1C200A08, // 002B EQ R8 R5 R8
0x78220016, // 002C JMPF R8 #0044
0x1C200D06, // 002D EQ R8 R6 K6
0x78220004, // 002E JMPF R8 #0034
0x50200000, // 002F LDBOOL R8 0 0
0x90021608, // 0030 SETMBR R0 K11 R8
0x50200200, // 0031 LDBOOL R8 1 0
0x80041000, // 0032 RET 1 R8
0x7002000F, // 0033 JMP #0044
0x1C200D07, // 0034 EQ R8 R6 K7
0x78220004, // 0035 JMPF R8 #003B
0x50200200, // 0036 LDBOOL R8 1 0
0x90021608, // 0037 SETMBR R0 K11 R8
0x50200200, // 0038 LDBOOL R8 1 0
0x80041000, // 0039 RET 1 R8
0x70020008, // 003A JMP #0044
0x1C200D0C, // 003B EQ R8 R6 K12
0x78220006, // 003C JMPF R8 #0044
0x8820010B, // 003D GETMBR R8 R0 K11
0x78220000, // 003E JMPF R8 #0040
0x50200001, // 003F LDBOOL R8 0 1
0x50200200, // 0040 LDBOOL R8 1 0
0x90021608, // 0041 SETMBR R0 K11 R8
0x50200200, // 0042 LDBOOL R8 1 0
0x80041000, // 0043 RET 1 R8
0x80000000, // 0044 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_Plugin_OnOff_init, /* name */
be_nested_proto(
5, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 6]) { /* constants */
/* K0 */ be_nested_str_weak(init),
/* K1 */ be_nested_str_weak(endpoints),
/* K2 */ be_nested_str_weak(ENDPOINTS),
/* K3 */ be_nested_str_weak(clusters),
/* K4 */ be_nested_str_weak(CLUSTERS),
/* K5 */ be_nested_str_weak(onoff),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[13]) { /* code */
0x60080003, // 0000 GETGBL R2 G3
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x8C080500, // 0003 GETMET R2 R2 K0
0x5C100200, // 0004 MOVE R4 R1
0x7C080400, // 0005 CALL R2 2
0x88080102, // 0006 GETMBR R2 R0 K2
0x90020202, // 0007 SETMBR R0 K1 R2
0x88080104, // 0008 GETMBR R2 R0 K4
0x90020602, // 0009 SETMBR R0 K3 R2
0x50080000, // 000A LDBOOL R2 0 0
0x90020A02, // 000B SETMBR R0 K5 R2
0x80000000, // 000C RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: read_attribute
********************************************************************/
be_local_closure(Matter_Plugin_OnOff_read_attribute, /* name */
be_nested_proto(
16, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[21]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(cluster),
/* K4 */ be_nested_str_weak(attribute),
/* K5 */ be_const_int(0),
/* K6 */ be_nested_str_weak(Matter_TLV_array),
/* K7 */ be_nested_str_weak(TYPES),
/* K8 */ be_nested_str_weak(add_struct),
/* K9 */ be_nested_str_weak(add_TLV),
/* K10 */ be_nested_str_weak(U2),
/* K11 */ be_const_int(1),
/* K12 */ be_nested_str_weak(stop_iteration),
/* K13 */ be_nested_str_weak(get_cluster_list),
/* K14 */ be_nested_str_weak(U4),
/* K15 */ be_const_int(2),
/* K16 */ be_const_int(3),
/* K17 */ be_nested_str_weak(create_TLV),
/* K18 */ be_nested_str_weak(U1),
/* K19 */ be_nested_str_weak(BOOL),
/* K20 */ be_nested_str_weak(onoff),
}),
be_str_weak(read_attribute),
&be_const_str_solidified,
( &(const binstruction[113]) { /* code */
0xA40E0000, // 0000 IMPORT R3 K0
0xB8120200, // 0001 GETNGBL R4 K1
0x88100902, // 0002 GETMBR R4 R4 K2
0x88140503, // 0003 GETMBR R5 R2 K3
0x88180504, // 0004 GETMBR R6 R2 K4
0x541E001C, // 0005 LDINT R7 29
0x1C1C0A07, // 0006 EQ R7 R5 R7
0x781E0042, // 0007 JMPF R7 #004B
0x1C1C0D05, // 0008 EQ R7 R6 K5
0x781E0019, // 0009 JMPF R7 #0024
0x8C1C0906, // 000A GETMET R7 R4 K6
0x7C1C0200, // 000B CALL R7 1
0x60200010, // 000C GETGBL R8 G16
0x88240107, // 000D GETMBR R9 R0 K7
0x7C200200, // 000E CALL R8 1
0xA802000E, // 000F EXBLK 0 #001F
0x5C241000, // 0010 MOVE R9 R8
0x7C240000, // 0011 CALL R9 0
0x8C280F08, // 0012 GETMET R10 R7 K8
0x7C280200, // 0013 CALL R10 1
0x8C2C1509, // 0014 GETMET R11 R10 K9
0x58340005, // 0015 LDCONST R13 K5
0x8838090A, // 0016 GETMBR R14 R4 K10
0x5C3C1200, // 0017 MOVE R15 R9
0x7C2C0800, // 0018 CALL R11 4
0x8C2C1509, // 0019 GETMET R11 R10 K9
0x5834000B, // 001A LDCONST R13 K11
0x8838090A, // 001B GETMBR R14 R4 K10
0x583C000B, // 001C LDCONST R15 K11
0x7C2C0800, // 001D CALL R11 4
0x7001FFF0, // 001E JMP #0010
0x5820000C, // 001F LDCONST R8 K12
0xAC200200, // 0020 CATCH R8 1 0
0xB0080000, // 0021 RAISE 2 R0 R0
0x80040E00, // 0022 RET 1 R7
0x70020025, // 0023 JMP #004A
0x1C1C0D0B, // 0024 EQ R7 R6 K11
0x781E0013, // 0025 JMPF R7 #003A
0x8C1C0906, // 0026 GETMET R7 R4 K6
0x7C1C0200, // 0027 CALL R7 1
0x60200010, // 0028 GETGBL R8 G16
0x8C24010D, // 0029 GETMET R9 R0 K13
0x7C240200, // 002A CALL R9 1
0x7C200200, // 002B CALL R8 1
0xA8020007, // 002C EXBLK 0 #0035
0x5C241000, // 002D MOVE R9 R8
0x7C240000, // 002E CALL R9 0
0x8C280F09, // 002F GETMET R10 R7 K9
0x4C300000, // 0030 LDNIL R12
0x8834090E, // 0031 GETMBR R13 R4 K14
0x5C381200, // 0032 MOVE R14 R9
0x7C280800, // 0033 CALL R10 4
0x7001FFF7, // 0034 JMP #002D
0x5820000C, // 0035 LDCONST R8 K12
0xAC200200, // 0036 CATCH R8 1 0
0xB0080000, // 0037 RAISE 2 R0 R0
0x80040E00, // 0038 RET 1 R7
0x7002000F, // 0039 JMP #004A
0x1C1C0D0F, // 003A EQ R7 R6 K15
0x781E0008, // 003B JMPF R7 #0045
0x8C1C0906, // 003C GETMET R7 R4 K6
0x7C1C0200, // 003D CALL R7 1
0x8C200F09, // 003E GETMET R8 R7 K9
0x4C280000, // 003F LDNIL R10
0x882C090A, // 0040 GETMBR R11 R4 K10
0x54320005, // 0041 LDINT R12 6
0x7C200800, // 0042 CALL R8 4
0x80040E00, // 0043 RET 1 R7
0x70020004, // 0044 JMP #004A
0x1C1C0D10, // 0045 EQ R7 R6 K16
0x781E0002, // 0046 JMPF R7 #004A
0x8C1C0906, // 0047 GETMET R7 R4 K6
0x7C1C0200, // 0048 CALL R7 1
0x80040E00, // 0049 RET 1 R7
0x70020024, // 004A JMP #0070
0x1C1C0B10, // 004B EQ R7 R5 K16
0x781E000F, // 004C JMPF R7 #005D
0x1C1C0D05, // 004D EQ R7 R6 K5
0x781E0005, // 004E JMPF R7 #0055
0x8C1C0911, // 004F GETMET R7 R4 K17
0x8824090A, // 0050 GETMBR R9 R4 K10
0x58280005, // 0051 LDCONST R10 K5
0x7C1C0600, // 0052 CALL R7 3
0x80040E00, // 0053 RET 1 R7
0x70020006, // 0054 JMP #005C
0x1C1C0D0B, // 0055 EQ R7 R6 K11
0x781E0004, // 0056 JMPF R7 #005C
0x8C1C0911, // 0057 GETMET R7 R4 K17
0x88240912, // 0058 GETMBR R9 R4 K18
0x58280005, // 0059 LDCONST R10 K5
0x7C1C0600, // 005A CALL R7 3
0x80040E00, // 005B RET 1 R7
0x70020012, // 005C JMP #0070
0x541E0005, // 005D LDINT R7 6
0x1C1C0A07, // 005E EQ R7 R5 R7
0x781E000F, // 005F JMPF R7 #0070
0x1C1C0D05, // 0060 EQ R7 R6 K5
0x781E0005, // 0061 JMPF R7 #0068
0x8C1C0911, // 0062 GETMET R7 R4 K17
0x88240913, // 0063 GETMBR R9 R4 K19
0x88280114, // 0064 GETMBR R10 R0 K20
0x7C1C0600, // 0065 CALL R7 3
0x80040E00, // 0066 RET 1 R7
0x70020007, // 0067 JMP #0070
0x541EFFFB, // 0068 LDINT R7 65532
0x1C1C0C07, // 0069 EQ R7 R6 R7
0x781E0004, // 006A JMPF R7 #0070
0x8C1C0911, // 006B GETMET R7 R4 K17
0x8824090E, // 006C GETMBR R9 R4 K14
0x58280005, // 006D LDCONST R10 K5
0x7C1C0600, // 006E CALL R7 3
0x80040E00, // 006F RET 1 R7
0x80000000, // 0070 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Plugin_OnOff
********************************************************************/
extern const bclass be_class_Matter_Plugin;
be_local_class(Matter_Plugin_OnOff,
1,
&be_class_Matter_Plugin,
be_nested_map(7,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_OnOff_invoke_request_closure) },
{ be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_OnOff_read_attribute_closure) },
{ be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_OnOff_init_closure) },
{ be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(256),
})) ) } )) },
{ be_const_key_weak(CLUSTERS, 6), be_const_simple_instance(be_nested_simple_instance(&be_class_map, {
be_const_map( * be_nested_map(5,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(6,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
be_const_int(1),
be_const_int(2),
be_const_int(3),
be_const_int(4),
be_const_int(5),
})) ) } )) },
{ be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(2,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
be_const_int(65532),
})) ) } )) },
{ be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(4,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
be_const_int(1),
be_const_int(2),
be_const_int(3),
})) ) } )) },
{ be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(2,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
be_const_int(1),
})) ) } )) },
{ be_const_key_int(4, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
})) ) } )) },
})) ) } )) },
{ be_const_key_weak(onoff, 2), be_const_var(0) },
{ be_const_key_weak(ENDPOINTS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(1),
})) ) } )) },
})),
be_str_weak(Matter_Plugin_OnOff)
);
/*******************************************************************/
void be_load_Matter_Plugin_OnOff_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Plugin_OnOff);
be_setglobal(vm, "Matter_Plugin_OnOff");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -1,246 +0,0 @@
/* Solidification of Matter_Plugin_Relay.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_Plugin_Relay;
/********************************************************************
** Solidified function: read_attribute
********************************************************************/
be_local_closure(Matter_Plugin_Relay_read_attribute, /* name */
be_nested_proto(
15, /* nstack */
3, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[17]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(cluster),
/* K4 */ be_nested_str_weak(attribute),
/* K5 */ be_const_int(0),
/* K6 */ be_nested_str_weak(Matter_TLV_array),
/* K7 */ be_nested_str_weak(add_struct),
/* K8 */ be_nested_str_weak(add_TLV),
/* K9 */ be_nested_str_weak(U2),
/* K10 */ be_nested_str_weak(TYPES),
/* K11 */ be_const_int(1),
/* K12 */ be_nested_str_weak(get_cluster_list),
/* K13 */ be_nested_str_weak(U4),
/* K14 */ be_nested_str_weak(stop_iteration),
/* K15 */ be_const_int(2),
/* K16 */ be_const_int(3),
}),
be_str_weak(read_attribute),
&be_const_str_solidified,
( &(const binstruction[66]) { /* code */
0xA40E0000, // 0000 IMPORT R3 K0
0xB8120200, // 0001 GETNGBL R4 K1
0x88100902, // 0002 GETMBR R4 R4 K2
0x88140503, // 0003 GETMBR R5 R2 K3
0x88180504, // 0004 GETMBR R6 R2 K4
0x541E001C, // 0005 LDINT R7 29
0x1C1C0A07, // 0006 EQ R7 R5 R7
0x781E0038, // 0007 JMPF R7 #0041
0x1C1C0D05, // 0008 EQ R7 R6 K5
0x781E0010, // 0009 JMPF R7 #001B
0x8C1C0906, // 000A GETMET R7 R4 K6
0x7C1C0200, // 000B CALL R7 1
0x8C200F07, // 000C GETMET R8 R7 K7
0x7C200200, // 000D CALL R8 1
0x8C241108, // 000E GETMET R9 R8 K8
0x582C0005, // 000F LDCONST R11 K5
0x88300909, // 0010 GETMBR R12 R4 K9
0x8834010A, // 0011 GETMBR R13 R0 K10
0x94341B05, // 0012 GETIDX R13 R13 K5
0x7C240800, // 0013 CALL R9 4
0x8C241108, // 0014 GETMET R9 R8 K8
0x582C000B, // 0015 LDCONST R11 K11
0x88300909, // 0016 GETMBR R12 R4 K9
0x5834000B, // 0017 LDCONST R13 K11
0x7C240800, // 0018 CALL R9 4
0x80040E00, // 0019 RET 1 R7
0x70020025, // 001A JMP #0041
0x1C1C0D0B, // 001B EQ R7 R6 K11
0x781E0013, // 001C JMPF R7 #0031
0x8C1C0906, // 001D GETMET R7 R4 K6
0x7C1C0200, // 001E CALL R7 1
0x60200010, // 001F GETGBL R8 G16
0x8C24010C, // 0020 GETMET R9 R0 K12
0x7C240200, // 0021 CALL R9 1
0x7C200200, // 0022 CALL R8 1
0xA8020007, // 0023 EXBLK 0 #002C
0x5C241000, // 0024 MOVE R9 R8
0x7C240000, // 0025 CALL R9 0
0x8C280F08, // 0026 GETMET R10 R7 K8
0x4C300000, // 0027 LDNIL R12
0x8834090D, // 0028 GETMBR R13 R4 K13
0x5C381200, // 0029 MOVE R14 R9
0x7C280800, // 002A CALL R10 4
0x7001FFF7, // 002B JMP #0024
0x5820000E, // 002C LDCONST R8 K14
0xAC200200, // 002D CATCH R8 1 0
0xB0080000, // 002E RAISE 2 R0 R0
0x80040E00, // 002F RET 1 R7
0x7002000F, // 0030 JMP #0041
0x1C1C0D0F, // 0031 EQ R7 R6 K15
0x781E0008, // 0032 JMPF R7 #003C
0x8C1C0906, // 0033 GETMET R7 R4 K6
0x7C1C0200, // 0034 CALL R7 1
0x8C200F08, // 0035 GETMET R8 R7 K8
0x4C280000, // 0036 LDNIL R10
0x882C0909, // 0037 GETMBR R11 R4 K9
0x54320005, // 0038 LDINT R12 6
0x7C200800, // 0039 CALL R8 4
0x80040E00, // 003A RET 1 R7
0x70020004, // 003B JMP #0041
0x1C1C0D10, // 003C EQ R7 R6 K16
0x781E0002, // 003D JMPF R7 #0041
0x8C1C0906, // 003E GETMET R7 R4 K6
0x7C1C0200, // 003F CALL R7 1
0x80040E00, // 0040 RET 1 R7
0x80000000, // 0041 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_Plugin_Relay_init, /* name */
be_nested_proto(
5, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 5]) { /* constants */
/* K0 */ be_nested_str_weak(init),
/* K1 */ be_nested_str_weak(endpoints),
/* K2 */ be_nested_str_weak(ENDPOINTS),
/* K3 */ be_nested_str_weak(clusters),
/* K4 */ be_nested_str_weak(CLUSTERS),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[11]) { /* code */
0x60080003, // 0000 GETGBL R2 G3
0x5C0C0000, // 0001 MOVE R3 R0
0x7C080200, // 0002 CALL R2 1
0x8C080500, // 0003 GETMET R2 R2 K0
0x5C100200, // 0004 MOVE R4 R1
0x7C080400, // 0005 CALL R2 2
0x88080102, // 0006 GETMBR R2 R0 K2
0x90020202, // 0007 SETMBR R0 K1 R2
0x88080104, // 0008 GETMBR R2 R0 K4
0x90020602, // 0009 SETMBR R0 K3 R2
0x80000000, // 000A RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: invoke_request
********************************************************************/
be_local_closure(Matter_Plugin_Relay_invoke_request, /* name */
be_nested_proto(
4, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
0, /* has constants */
NULL, /* no const */
be_str_weak(invoke_request),
&be_const_str_solidified,
( &(const binstruction[ 1]) { /* code */
0x80000000, // 0000 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Plugin_Relay
********************************************************************/
extern const bclass be_class_Matter_Plugin;
be_local_class(Matter_Plugin_Relay,
0,
&be_class_Matter_Plugin,
be_nested_map(6,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) },
{ be_const_key_weak(ENDPOINTS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(1),
})) ) } )) },
{ be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(256),
})) ) } )) },
{ be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Relay_init_closure) },
{ be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, {
be_const_map( * be_nested_map(6,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(1,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
})) ) } )) },
{ be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(4,
( (struct bvalue*) &(const bvalue[]) {
be_const_int(0),
be_const_int(1),
be_const_int(2),
be_const_int(3),
})) ) } )) },
{ be_const_key_int(8, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(0,
( (struct bvalue*) &(const bvalue[]) {
})) ) } )) },
{ be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(0,
( (struct bvalue*) &(const bvalue[]) {
})) ) } )) },
{ be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(0,
( (struct bvalue*) &(const bvalue[]) {
})) ) } )) },
{ be_const_key_int(5, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, {
be_const_list( * be_nested_list(0,
( (struct bvalue*) &(const bvalue[]) {
})) ) } )) },
})) ) } )) },
{ be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Relay_invoke_request_closure) },
})),
be_str_weak(Matter_Plugin_Relay)
);
/*******************************************************************/
void be_load_Matter_Plugin_Relay_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Plugin_Relay);
be_setglobal(vm, "Matter_Plugin_Relay");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@ be_local_closure(Matter_UDPPacket_sent_send, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[14]) { /* constants */
( &(const bvalue[13]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(send),
/* K2 */ be_nested_str_weak(addr),
@ -78,9 +78,8 @@ be_local_closure(Matter_UDPPacket_sent_send, /* name */
/* K8 */ be_nested_str_weak(log),
/* K9 */ be_nested_str_weak(format),
/* K10 */ be_nested_str_weak(MTR_X3A_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27),
/* K11 */ be_const_int(3),
/* K12 */ be_nested_str_weak(MTR_X3A_X20failed_X20to_X20send_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27),
/* K13 */ be_const_int(2),
/* K11 */ be_nested_str_weak(MTR_X3A_X20error_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27),
/* K12 */ be_const_int(3),
}),
be_str_weak(send),
&be_const_str_solidified,
@ -107,17 +106,17 @@ be_local_closure(Matter_UDPPacket_sent_send, /* name */
0x88240102, // 0013 GETMBR R9 R0 K2
0x88280104, // 0014 GETMBR R10 R0 K4
0x7C180800, // 0015 CALL R6 4
0x581C000B, // 0016 LDCONST R7 K11
0x541E0003, // 0016 LDINT R7 4
0x7C100600, // 0017 CALL R4 3
0x70020008, // 0018 JMP #0022
0xB8120E00, // 0019 GETNGBL R4 K7
0x8C100908, // 001A GETMET R4 R4 K8
0x8C180509, // 001B GETMET R6 R2 K9
0x5820000C, // 001C LDCONST R8 K12
0x5820000B, // 001C LDCONST R8 K11
0x88240102, // 001D GETMBR R9 R0 K2
0x88280104, // 001E GETMBR R10 R0 K4
0x7C180800, // 001F CALL R6 4
0x581C000D, // 0020 LDCONST R7 K13
0x581C000C, // 0020 LDCONST R7 K12
0x7C100600, // 0021 CALL R4 3
0x80000000, // 0022 RET 0
})
@ -357,7 +356,7 @@ be_local_closure(Matter_UDPServer_every_50ms, /* name */
********************************************************************/
be_local_closure(Matter_UDPServer_resend_packets, /* name */
be_nested_proto(
7, /* nstack */
11, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
@ -365,7 +364,7 @@ be_local_closure(Matter_UDPServer_resend_packets, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[17]) { /* constants */
( &(const bvalue[22]) { /* constants */
/* K0 */ be_nested_str_weak(packets_sent),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(time_reached),
@ -379,25 +378,30 @@ be_local_closure(Matter_UDPServer_resend_packets, /* name */
/* K10 */ be_nested_str_weak(retries),
/* K11 */ be_const_int(1),
/* K12 */ be_const_int(0),
/* K13 */ be_nested_str_weak(remove),
/* K14 */ be_nested_str_weak(millis),
/* K15 */ be_nested_str_weak(RETRY_MS),
/* K16 */ be_nested_str_weak(stop_iteration),
/* K13 */ be_nested_str_weak(string),
/* K14 */ be_nested_str_weak(remove),
/* K15 */ be_nested_str_weak(format),
/* K16 */ be_nested_str_weak(MTR_X3A_X20non_X2Dacked_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27),
/* K17 */ be_nested_str_weak(addr),
/* K18 */ be_nested_str_weak(port),
/* K19 */ be_nested_str_weak(millis),
/* K20 */ be_nested_str_weak(RETRY_MS),
/* K21 */ be_nested_str_weak(stop_iteration),
}),
be_str_weak(resend_packets),
&be_const_str_solidified,
( &(const binstruction[44]) { /* code */
( &(const binstruction[54]) { /* code */
0x60040010, // 0000 GETGBL R1 G16
0x88080100, // 0001 GETMBR R2 R0 K0
0x7C040200, // 0002 CALL R1 1
0xA8020023, // 0003 EXBLK 0 #0028
0xA802002D, // 0003 EXBLK 0 #0032
0x5C080200, // 0004 MOVE R2 R1
0x7C080000, // 0005 CALL R2 0
0xB80E0200, // 0006 GETNGBL R3 K1
0x8C0C0702, // 0007 GETMET R3 R3 K2
0x88140503, // 0008 GETMBR R5 R2 K3
0x7C0C0400, // 0009 CALL R3 2
0x780E001B, // 000A JMPF R3 #0027
0x780E0025, // 000A JMPF R3 #0031
0xB80E0200, // 000B GETNGBL R3 K1
0x8C0C0704, // 000C GETMET R3 R3 K4
0x60140008, // 000D GETGBL R5 G8
@ -414,23 +418,33 @@ be_local_closure(Matter_UDPServer_resend_packets, /* name */
0x900A1403, // 0018 SETMBR R2 K10 R3
0x880C050A, // 0019 GETMBR R3 R2 K10
0x180C070C, // 001A LE R3 R3 K12
0x780E0004, // 001B JMPF R3 #0021
0x880C0100, // 001C GETMBR R3 R0 K0
0x8C0C070D, // 001D GETMET R3 R3 K13
0x88140506, // 001E GETMBR R5 R2 K6
0x7C0C0400, // 001F CALL R3 2
0x70020005, // 0020 JMP #0027
0xB80E0200, // 0021 GETNGBL R3 K1
0x8C0C070E, // 0022 GETMET R3 R3 K14
0x7C0C0200, // 0023 CALL R3 1
0x8810050F, // 0024 GETMBR R4 R2 K15
0x000C0604, // 0025 ADD R3 R3 R4
0x900A0603, // 0026 SETMBR R2 K3 R3
0x7001FFDB, // 0027 JMP #0004
0x58040010, // 0028 LDCONST R1 K16
0xAC040200, // 0029 CATCH R1 1 0
0xB0080000, // 002A RAISE 2 R0 R0
0x80000000, // 002B RET 0
0x780E000E, // 001B JMPF R3 #002B
0xA40E1A00, // 001C IMPORT R3 K13
0x88100100, // 001D GETMBR R4 R0 K0
0x8C10090E, // 001E GETMET R4 R4 K14
0x88180506, // 001F GETMBR R6 R2 K6
0x7C100400, // 0020 CALL R4 2
0xB8120200, // 0021 GETNGBL R4 K1
0x8C100904, // 0022 GETMET R4 R4 K4
0x8C18070F, // 0023 GETMET R6 R3 K15
0x58200010, // 0024 LDCONST R8 K16
0x88240511, // 0025 GETMBR R9 R2 K17
0x88280512, // 0026 GETMBR R10 R2 K18
0x7C180800, // 0027 CALL R6 4
0x581C0007, // 0028 LDCONST R7 K7
0x7C100600, // 0029 CALL R4 3
0x70020005, // 002A JMP #0031
0xB80E0200, // 002B GETNGBL R3 K1
0x8C0C0713, // 002C GETMET R3 R3 K19
0x7C0C0200, // 002D CALL R3 1
0x88100514, // 002E GETMBR R4 R2 K20
0x000C0604, // 002F ADD R3 R3 R4
0x900A0603, // 0030 SETMBR R2 K3 R3
0x7001FFD1, // 0031 JMP #0004
0x58040015, // 0032 LDCONST R1 K21
0xAC040200, // 0033 CATCH R1 1 0
0xB0080000, // 0034 RAISE 2 R0 R0
0x80000000, // 0035 RET 0
})
)
);
@ -549,14 +563,13 @@ be_local_closure(Matter_UDPServer_packet_ack, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 7]) { /* constants */
( &(const bvalue[ 6]) { /* constants */
/* K0 */ be_nested_str_weak(packets_sent),
/* K1 */ be_nested_str_weak(contains),
/* K2 */ be_nested_str_weak(remove),
/* K3 */ be_nested_str_weak(tasmota),
/* K4 */ be_nested_str_weak(log),
/* K5 */ be_nested_str_weak(MTR_X3A_X20removed_X20packet_X20from_X20sending_X20list_X20id_X3D),
/* K6 */ be_const_int(3),
}),
be_str_weak(packet_ack),
&be_const_str_solidified,
@ -580,7 +593,7 @@ be_local_closure(Matter_UDPServer_packet_ack, /* name */
0x5C140200, // 0010 MOVE R5 R1
0x7C100200, // 0011 CALL R4 1
0x00120A04, // 0012 ADD R4 K5 R4
0x58140006, // 0013 LDCONST R5 K6
0x54160003, // 0013 LDINT R5 4
0x7C080600, // 0014 CALL R2 3
0x80000000, // 0015 RET 0
})