ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) (#17871)

* ESP32 preliminary support for Matter protocol, milestone 1 (commissioning)

* Fix case
This commit is contained in:
s-hadinger 2023-02-04 00:00:21 +01:00 committed by GitHub
parent e8056df1ad
commit a483991ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 37404 additions and 4 deletions

View File

@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736)
- Berry add ``mdns`` advanced features and query
- ESP32 support for Biomine BioPDU 625x12 (#17857)
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning)
### Breaking Changed
- Berry energy_ctypes changed with new energy driver

View File

@ -65,6 +65,9 @@ be_extern_native_module(lv_tasmota);
be_extern_native_module(haspmota);
#endif // USE_LVGL_HASPMOTA
#endif // USE_LVGL
#ifdef USE_MATTER_DEVICE
be_extern_native_module(matter);
#endif // USE_MATTER_DEVICE
/* user-defined modules declare start */
@ -175,6 +178,9 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
#ifdef USE_DISCOVERY
&be_native_module(mdns),
#endif // USE_DISCOVERY
#ifdef USE_MATTER_DEVICE
&be_native_module(matter),
#endif // USE_MATTER_DEVICE
#endif // TASMOTA
/* user-defined modules register end */
NULL /* do not remove */

View File

@ -0,0 +1,121 @@
# ../../berry/berry -s -g Matter_generate_c.be
#
# generate C headers
import matter_clusters
var c = matter_clusters
#################################################################################
# Simple insertion sort - sorts the list in place, and returns the list
#################################################################################
def sort(l) 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
# keys to llist
def k2l(m) var r=[] for k:m.keys() r.push(k) end return sort(r) end
var cl_keys = {}
for cl:c
for k:cl.keys()
cl_keys[k] = true
end
end
var attr_ids = {}
var attr_keys = {}
var attr_types = {}
for cl:c
for attr:cl['attributes']
attr_ids[attr['attributeId']] = true
for k:attr.keys()
attr_keys[k] = true
end
attr_types[attr['type']] = true
end
end
import string
# prepare file
f=open("be_matter_clusters.h", "w")
def fprint(*l)
f.write(l.concat(" "))
f.write("\n")
end
# fprint("Cluster keys:",k2l(cl_keys))
# fprint("Attribute ids:",k2l(attr_ids))
# fprint("Attribute keys:",k2l(attr_keys))
# fprint("Attribute types:",k2l(attr_types))
var cl_id_name = {}
for cl:c
cl_id_name[cl['clusterId']] = cl['clusterName']
end
var cl_ids = k2l(cl_id_name)
fprint("/*********************************************************************************\\")
fprint("* Compact form for attributes and clusters")
fprint("*")
fprint("* Generated content, do not edit")
fprint("\\*********************************************************************************/")
fprint()
fprint("typedef struct {")
fprint(" uint16_t id;")
fprint(" uint8_t type;")
fprint(" uint8_t flags;")
fprint(" const char* name;")
fprint("} matter_attribute_t;")
fprint()
fprint("typedef struct {")
fprint(" uint16_t id;")
fprint(" const char* name;")
fprint("} matter_command_t;")
fprint()
fprint("typedef struct {")
fprint(" uint16_t id;")
fprint(" const char* name;")
fprint(" const matter_attribute_t* attributes;")
fprint(" const matter_command_t* commands;")
fprint("} matter_cluster_t;")
fprint()
for cl:cl_ids
fprint(string.format("const matter_attribute_t matter_Attributes_%04X[] = {", cl))
var attributes = c[cl_id_name[cl]]['attributes']
var attr_id_name = {}
for attr:attributes
attr_id_name[attr['attributeId']] = attr['attributeName']
end
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']))
end
fprint(' { 0xFFFF, 0, 0x00, NULL },')
fprint("};")
fprint()
# commands
fprint(string.format("const matter_command_t matter_Commands_%04X[] = {", cl))
var commands = c[cl_id_name[cl]]['commands']
var cmd_id_name = {}
for cmd:commands
cmd_id_name[cmd['commandId']] = cmd['commandName']
end
var cmd_ids_local = k2l(cmd_id_name)
for cmd_id:cmd_ids_local
fprint(string.format(' { 0x%04X, "%s" },', cmd_id, commands[cmd_id]['commandName']))
end
fprint(' { 0xFFFF, NULL },')
fprint("};")
fprint()
end
fprint("const matter_cluster_t matterAllClusters[] = {")
for cl:cl_ids
fprint(string.format(' { 0x%04X, "%s", matter_Attributes_%04X, matter_Commands_%04X },', cl, cl_id_name[cl], cl, cl))
end
fprint(' { 0xFFFF, NULL, NULL },')
fprint("};")
f.close()

View File

@ -0,0 +1,351 @@
// Certificates and credentials from demo
#include <stddef.h>
#include <stdint.h>
const uint8_t kDevelopmentPAI_Cert_FFF1[463] = {
0x30, 0x82, 0x01, 0xcb, 0x30, 0x82, 0x01, 0x71, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x56, 0xad, 0x82, 0x22, 0xad, 0x94,
0x5b, 0x64, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x30, 0x31, 0x18, 0x30, 0x16, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x41, 0x41,
0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46,
0x31, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39,
0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3d, 0x31, 0x25, 0x30, 0x23, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x50, 0x41, 0x49, 0x20,
0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x20, 0x6e, 0x6f, 0x20, 0x50, 0x49, 0x44, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x41,
0x9a, 0x93, 0x15, 0xc2, 0x17, 0x3e, 0x0c, 0x8c, 0x87, 0x6d, 0x03, 0xcc, 0xfc, 0x94, 0x48, 0x52, 0x64, 0x7f, 0x7f, 0xec, 0x5e,
0x50, 0x82, 0xf4, 0x05, 0x99, 0x28, 0xec, 0xa8, 0x94, 0xc5, 0x94, 0x15, 0x13, 0x09, 0xac, 0x63, 0x1e, 0x4c, 0xb0, 0x33, 0x92,
0xaf, 0x68, 0x4b, 0x0b, 0xaf, 0xb7, 0xe6, 0x5b, 0x3b, 0x81, 0x62, 0xc2, 0xf5, 0x2b, 0xf9, 0x31, 0xb8, 0xe7, 0x7a, 0xaa, 0x82,
0xa3, 0x66, 0x30, 0x64, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff,
0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x63, 0x54, 0x0e, 0x47, 0xf6, 0x4b, 0x1c, 0x38, 0xd1, 0x38, 0x84, 0xa4,
0x62, 0xd1, 0x6c, 0x19, 0x5d, 0x8f, 0xfb, 0x3c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
0x6a, 0xfd, 0x22, 0x77, 0x1f, 0x51, 0x1f, 0xec, 0xbf, 0x16, 0x41, 0x97, 0x67, 0x10, 0xdc, 0xdc, 0x31, 0xa1, 0x71, 0x7e, 0x30,
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb2, 0xef,
0x27, 0xf4, 0x9a, 0xe9, 0xb5, 0x0f, 0xb9, 0x1e, 0xea, 0xc9, 0x4c, 0x4d, 0x0b, 0xdb, 0xb8, 0xd7, 0x92, 0x9c, 0x6c, 0xb8, 0x8f,
0xac, 0xe5, 0x29, 0x36, 0x8d, 0x12, 0x05, 0x4c, 0x0c, 0x02, 0x20, 0x65, 0x5d, 0xc9, 0x2b, 0x86, 0xbd, 0x90, 0x98, 0x82, 0xa6,
0xc6, 0x21, 0x77, 0xb8, 0x25, 0xd7, 0xd0, 0x5e, 0xdb, 0xe7, 0xc2, 0x2f, 0x9f, 0xea, 0x71, 0x22, 0x0e, 0x7e, 0xa7, 0x03, 0xf8,
0x91,
};
const uint8_t kDevelopmentPAI_PublicKey_FFF1[65] = {
0x04, 0x41, 0x9a, 0x93, 0x15, 0xc2, 0x17, 0x3e, 0x0c, 0x8c, 0x87, 0x6d, 0x03, 0xcc, 0xfc, 0x94, 0x48,
0x52, 0x64, 0x7f, 0x7f, 0xec, 0x5e, 0x50, 0x82, 0xf4, 0x05, 0x99, 0x28, 0xec, 0xa8, 0x94, 0xc5, 0x94,
0x15, 0x13, 0x09, 0xac, 0x63, 0x1e, 0x4c, 0xb0, 0x33, 0x92, 0xaf, 0x68, 0x4b, 0x0b, 0xaf, 0xb7, 0xe6,
0x5b, 0x3b, 0x81, 0x62, 0xc2, 0xf5, 0x2b, 0xf9, 0x31, 0xb8, 0xe7, 0x7a, 0xaa, 0x82,
};
const uint8_t kDevelopmentPAI_PrivateKey_FFF1[32] = {
0xc1, 0xab, 0x5f, 0xe2, 0x84, 0xb4, 0xc1, 0x89, 0x40, 0xa5, 0x31, 0x61, 0xf8, 0x06, 0x94, 0x40,
0x50, 0xa1, 0x69, 0x7b, 0x71, 0x76, 0x1d, 0x38, 0x53, 0x37, 0xa8, 0xa3, 0xcd, 0x09, 0x5c, 0x34,
};
/*
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
56:ad:82:22:ad:94:5b:64
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN = Matter Test PAA, 1.3.6.1.4.1.37244.2.1 = FFF1
Validity
Not Before: Feb 5 00:00:00 2022 GMT
Not After : Dec 31 23:59:59 9999 GMT
Subject: CN = Matter Dev PAI 0xFFF1 no PID, 1.3.6.1.4.1.37244.2.1 = FFF1
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:41:9a:93:15:c2:17:3e:0c:8c:87:6d:03:cc:fc:
94:48:52:64:7f:7f:ec:5e:50:82:f4:05:99:28:ec:
a8:94:c5:94:15:13:09:ac:63:1e:4c:b0:33:92:af:
68:4b:0b:af:b7:e6:5b:3b:81:62:c2:f5:2b:f9:31:
b8:e7:7a:aa:82
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Subject Key Identifier:
63:54:0E:47:F6:4B:1C:38:D1:38:84:A4:62:D1:6C:19:5D:8F:FB:3C
X509v3 Authority Key Identifier:
keyid:6A:FD:22:77:1F:51:1F:EC:BF:16:41:97:67:10:DC:DC:31:A1:71:7E
Signature Algorithm: ecdsa-with-SHA256
30:45:02:21:00:b2:ef:27:f4:9a:e9:b5:0f:b9:1e:ea:c9:4c:
4d:0b:db:b8:d7:92:9c:6c:b8:8f:ac:e5:29:36:8d:12:05:4c:
0c:02:20:65:5d:c9:2b:86:bd:90:98:82:a6:c6:21:77:b8:25:
d7:d0:5e:db:e7:c2:2f:9f:ea:71:22:0e:7e:a7:03:f8:91
*/
/*
ASN.1
SEQUENCE (3 elem)
SEQUENCE (8 elem)
[0] (1 elem)
INTEGER 2
INTEGER (63 bit) 6245791343685426020
SEQUENCE (1 elem)
OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
SEQUENCE (2 elem)
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
UTF8String Matter Test PAA
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1
UTF8String FFF1
SEQUENCE (2 elem)
UTCTime 2022-02-05 00:00:00 UTC
GeneralizedTime 9999-12-31 23:59:59 UTC
SEQUENCE (2 elem)
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
UTF8String Matter Dev PAI 0xFFF1 no PID
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1
UTF8String FFF1
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
BIT STRING (520 bit) 0000010001000001100110101001001100010101110000100001011100111110000011
[3] (1 elem)
SEQUENCE (4 elem)
SEQUENCE (3 elem)
OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
BOOLEAN true
OCTET STRING (8 byte) 30060101FF020100
SEQUENCE (2 elem)
BOOLEAN true
INTEGER 0
SEQUENCE (3 elem)
OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension)
BOOLEAN true
OCTET STRING (4 byte) 03020106
BIT STRING (7 bit) 0000011
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension)
OCTET STRING (22 byte) 041463540E47F64B1C38D13884A462D16C195D8FFB3C
OCTET STRING (20 byte) 63540E47F64B1C38D13884A462D16C195D8FFB3C
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.29.35 authorityKeyIdentifier (X.509 extension)
OCTET STRING (24 byte) 301680146AFD22771F511FECBF1641976710DCDC31A1717E
SEQUENCE (1 elem)
[0] (20 byte) 6AFD22771F511FECBF1641976710DCDC31A1717E
SEQUENCE (1 elem)
Offset: 377
Length: 2+10
(constructed)
Value:
(1 elem)
OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
BIT STRING (568 bit) 0011000001000101000000100010000100000000101100101110111100100111111101
SEQUENCE (2 elem)
INTEGER (256 bit) 8093423925895219711386938045632983408737245943652937189339272815747009
INTEGER (255 bit) 4584930290841753608947726397552150715869097421278636946745345682393985
*/
const uint8_t kDevelopmentDAC_Cert_FFF1_8000[493] = {
0x30, 0x82, 0x01, 0xe9, 0x30, 0x82, 0x01, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x23, 0x8a, 0x64, 0x7b, 0xbc, 0x4c,
0x30, 0xdd, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x3d, 0x31, 0x25, 0x30, 0x23, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x50, 0x41, 0x49, 0x20,
0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x20, 0x6e, 0x6f, 0x20, 0x50, 0x49, 0x44, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30,
0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32,
0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61,
0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x44, 0x41, 0x43, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x2f, 0x30,
0x78, 0x38, 0x30, 0x30, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01,
0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02,
0x02, 0x0c, 0x04, 0x38, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x62, 0xdb, 0x16, 0xba, 0xde, 0xa3, 0x26, 0xa6,
0xdb, 0x84, 0x81, 0x4a, 0x06, 0x3f, 0xc6, 0xc7, 0xe9, 0xe2, 0xb1, 0x01, 0xb7, 0x21, 0x64, 0x8e, 0xba, 0x4e, 0x5a, 0xc8, 0x40,
0xf5, 0xda, 0x30, 0x1e, 0xe6, 0x18, 0x12, 0x4e, 0xb4, 0x18, 0x0e, 0x2f, 0xc3, 0xa2, 0x04, 0x7a, 0x56, 0x4b, 0xa9, 0xbc, 0xfa,
0x0b, 0xf7, 0x1f, 0x60, 0xce, 0x89, 0x30, 0xf1, 0xe7, 0xf6, 0x6e, 0xc8, 0xd7, 0x28, 0xa3, 0x60, 0x30, 0x5e, 0x30, 0x0c, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xbc, 0xf7, 0xb0, 0x07,
0x49, 0x70, 0x63, 0x60, 0x6a, 0x26, 0xbe, 0x4e, 0x08, 0x7c, 0x59, 0x56, 0x87, 0x74, 0x5a, 0x5a, 0x30, 0x1f, 0x06, 0x03, 0x55,
0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x63, 0x54, 0x0e, 0x47, 0xf6, 0x4b, 0x1c, 0x38, 0xd1, 0x38, 0x84, 0xa4, 0x62,
0xd1, 0x6c, 0x19, 0x5d, 0x8f, 0xfb, 0x3c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49,
0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x97, 0x97, 0x11, 0xec, 0x9e, 0x76, 0x18, 0xce, 0x41, 0x80, 0x11, 0x32, 0xc2, 0x50, 0xdb,
0x70, 0x76, 0x74, 0x63, 0x0c, 0xd5, 0x8c, 0x12, 0xc6, 0xe2, 0x31, 0x5f, 0x08, 0xd0, 0x1e, 0xe1, 0x78, 0x02, 0x21, 0x00, 0xec,
0xfc, 0x13, 0x06, 0xbd, 0x2a, 0x13, 0x3d, 0x12, 0x2a, 0x27, 0x86, 0x10, 0xea, 0x3d, 0xca, 0x47, 0xf0, 0x5c, 0x7a, 0x8b, 0x80,
0x5f, 0xa7, 0x1c, 0x6f, 0xf4, 0x15, 0x38, 0xa8, 0x64, 0xc8,
};
/*
Decoded cert: openssl x509 -inform der -in DAC_Cert_FFF1_8000.der -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
23:8a:64:7b:bc:4c:30:dd
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN = Matter Dev PAI 0xFFF1 no PID, 1.3.6.1.4.1.37244.2.1 = FFF1
Validity
Not Before: Feb 5 00:00:00 2022 GMT
Not After : Dec 31 23:59:59 9999 GMT
Subject: CN = Matter Dev DAC 0xFFF1/0x8000, 1.3.6.1.4.1.37244.2.1 = FFF1, 1.3.6.1.4.1.37244.2.2 = 8000
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:62:db:16:ba:de:a3:26:a6:db:84:81:4a:06:3f:
c6:c7:e9:e2:b1:01:b7:21:64:8e:ba:4e:5a:c8:40:
f5:da:30:1e:e6:18:12:4e:b4:18:0e:2f:c3:a2:04:
7a:56:4b:a9:bc:fa:0b:f7:1f:60:ce:89:30:f1:e7:
f6:6e:c8:d7:28
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature
X509v3 Subject Key Identifier:
BC:F7:B0:07:49:70:63:60:6A:26:BE:4E:08:7C:59:56:87:74:5A:5A
X509v3 Authority Key Identifier:
keyid:63:54:0E:47:F6:4B:1C:38:D1:38:84:A4:62:D1:6C:19:5D:8F:FB:3C
Signature Algorithm: ecdsa-with-SHA256
30:46:02:21:00:97:97:11:ec:9e:76:18:ce:41:80:11:32:c2:
50:db:70:76:74:63:0c:d5:8c:12:c6:e2:31:5f:08:d0:1e:e1:
78:02:21:00:ec:fc:13:06:bd:2a:13:3d:12:2a:27:86:10:ea:
3d:ca:47:f0:5c:7a:8b:80:5f:a7:1c:6f:f4:15:38:a8:64:c8
*/
/* Decoded ASN.1
SEQUENCE (3 elem)
SEQUENCE (8 elem)
[0] (1 elem)
INTEGER 2
INTEGER (62 bit) 2560969820716413149
SEQUENCE (1 elem)
OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
SEQUENCE (2 elem)
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
UTF8String Matter Dev PAI 0xFFF1 no PID
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1
UTF8String FFF1
SEQUENCE (2 elem)
UTCTime 2022-02-05 00:00:00 UTC
GeneralizedTime 9999-12-31 23:59:59 UTC
SEQUENCE (3 elem)
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
UTF8String Matter Dev DAC 0xFFF1/0x8000
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1
UTF8String FFF1
SET (1 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.2
UTF8String 8000
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
BIT STRING (520 bit) 0000010001100010110110110001011010111010110111101010001100100110101001
[3] (1 elem)
SEQUENCE (4 elem)
SEQUENCE (3 elem)
OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
BOOLEAN true
OCTET STRING (2 byte) 3000
SEQUENCE (0 elem)
SEQUENCE (3 elem)
OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension)
BOOLEAN true
OCTET STRING (4 byte) 03020780
BIT STRING (1 bit) 1
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension)
OCTET STRING (22 byte) 0414BCF7B007497063606A26BE4E087C595687745A5A
OCTET STRING (20 byte) BCF7B007497063606A26BE4E087C595687745A5A
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.5.29.35 authorityKeyIdentifier (X.509 extension)
OCTET STRING (24 byte) 3016801463540E47F64B1C38D13884A462D16C195D8FFB3C
SEQUENCE (1 elem)
[0] (20 byte) 63540E47F64B1C38D13884A462D16C195D8FFB3C
SEQUENCE (1 elem)
OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
BIT STRING (576 bit) 0011000001000110000000100010000100000000100101111001011100010001111011
SEQUENCE (2 elem)
INTEGER (256 bit) 6856615775177799389454949658700013485116050405241433595512074226650010
INTEGER (256 bit) 1071912090408366213691559168363210336766445086127676108978024779974417
*/
const uint8_t kDevelopmentDAC_PublicKey_FFF1_8000[65] = {
0x04, 0x62, 0xdb, 0x16, 0xba, 0xde, 0xa3, 0x26, 0xa6, 0xdb, 0x84, 0x81, 0x4a, 0x06, 0x3f, 0xc6, 0xc7,
0xe9, 0xe2, 0xb1, 0x01, 0xb7, 0x21, 0x64, 0x8e, 0xba, 0x4e, 0x5a, 0xc8, 0x40, 0xf5, 0xda, 0x30, 0x1e,
0xe6, 0x18, 0x12, 0x4e, 0xb4, 0x18, 0x0e, 0x2f, 0xc3, 0xa2, 0x04, 0x7a, 0x56, 0x4b, 0xa9, 0xbc, 0xfa,
0x0b, 0xf7, 0x1f, 0x60, 0xce, 0x89, 0x30, 0xf1, 0xe7, 0xf6, 0x6e, 0xc8, 0xd7, 0x28,
};
const uint8_t kDevelopmentDAC_PrivateKey_FFF1_8000[32] = {
0xcc, 0xcf, 0x9d, 0xc7, 0x05, 0x0e, 0xf5, 0xd9, 0x0b, 0xe4, 0x57, 0x07, 0xb9, 0x0e, 0x1f, 0x87,
0x5d, 0x59, 0xbe, 0x1f, 0xa9, 0x42, 0xe8, 0xed, 0x2e, 0x42, 0x72, 0x03, 0xf6, 0xc2, 0xee, 0x3d,
};
/* CertificationDeclaration */
//-> format_version = 1
//-> vendor_id = 0xFFF1
//-> product_id_array = [ 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, 0x8005, 0x8006, 0x8007, 0x8008, 0x8009, 0x800A, 0x800B,
// 0x800C, 0x800D, 0x800E, 0x800F, 0x8010, 0x8011, 0x8012, 0x8013, 0x8014, 0x8015, 0x8016, 0x8017, 0x8018, 0x8019, 0x801A,
// 0x801B, 0x801C, 0x801D, 0x801E, 0x801F, 0x8020, 0x8021, 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x8027, 0x8028, 0x8029,
// 0x802A, 0x802B, 0x802C, 0x802D, 0x802E, 0x802F, 0x8030, 0x8031, 0x8032, 0x8033, 0x8034, 0x8035, 0x8036, 0x8037, 0x8038,
// 0x8039, 0x803A, 0x803B, 0x803C, 0x803D, 0x803E, 0x803F, 0x8040, 0x8041, 0x8042, 0x8043, 0x8044, 0x8045, 0x8046, 0x8047,
// 0x8048, 0x8049, 0x804A, 0x804B, 0x804C, 0x804D, 0x804E, 0x804F, 0x8050, 0x8051, 0x8052, 0x8053, 0x8054, 0x8055, 0x8056,
// 0x8057, 0x8058, 0x8059, 0x805A, 0x805B, 0x805C, 0x805D, 0x805E, 0x805F, 0x8060, 0x8061, 0x8062, 0x8063 ]
//-> device_type_id = 0x0016
//-> certificate_id = "CSA00000SWC00000-00"
//-> security_level = 0
//-> security_information = 0
//-> version_number = 1
//-> certification_type = 0
//-> dac_origin_vendor_id is not present
//-> dac_origin_product_id is not present
const uint8_t kCdForAllExamples[539] = {
0x30, 0x82, 0x02, 0x17, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x08, 0x30,
0x82, 0x02, 0x04, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
0x01, 0x30, 0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0x61,
0x04, 0x82, 0x01, 0x5d, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf1, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, 0x05, 0x01, 0x80,
0x05, 0x02, 0x80, 0x05, 0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, 0x07, 0x80, 0x05, 0x08,
0x80, 0x05, 0x09, 0x80, 0x05, 0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, 0x80, 0x05, 0x0e, 0x80, 0x05,
0x0f, 0x80, 0x05, 0x10, 0x80, 0x05, 0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, 0x05, 0x14, 0x80, 0x05, 0x15, 0x80,
0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05, 0x18, 0x80, 0x05, 0x19, 0x80, 0x05, 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c,
0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05, 0x1f, 0x80, 0x05, 0x20, 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05,
0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05, 0x26, 0x80, 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80,
0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05, 0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30,
0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, 0x80, 0x05, 0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05,
0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, 0x05, 0x3a, 0x80, 0x05, 0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80,
0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, 0x40, 0x80, 0x05, 0x41, 0x80, 0x05, 0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44,
0x80, 0x05, 0x45, 0x80, 0x05, 0x46, 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05, 0x49, 0x80, 0x05, 0x4a, 0x80, 0x05,
0x4b, 0x80, 0x05, 0x4c, 0x80, 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05, 0x50, 0x80, 0x05, 0x51, 0x80,
0x05, 0x52, 0x80, 0x05, 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05, 0x57, 0x80, 0x05, 0x58,
0x80, 0x05, 0x59, 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05, 0x5e, 0x80, 0x05,
0x5f, 0x80, 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16, 0x2c, 0x04,
0x13, 0x43, 0x53, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x53, 0x57, 0x43, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30, 0x30,
0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x24, 0x07, 0x01, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7c, 0x30, 0x7a, 0x02, 0x01, 0x03,
0x80, 0x14, 0xfe, 0x34, 0x3f, 0x95, 0x99, 0x47, 0x76, 0x3b, 0x61, 0xee, 0x45, 0x39, 0x13, 0x13, 0x38, 0x49, 0x4f, 0xe6,
0x7d, 0x8e, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x4a, 0x12, 0xf8, 0xd4, 0x2f, 0x90, 0x23,
0x5c, 0x05, 0xa7, 0x71, 0x21, 0xcb, 0xeb, 0xae, 0x15, 0xd5, 0x90, 0x14, 0x65, 0x58, 0xe9, 0xc9, 0xb4, 0x7a, 0x1a, 0x38,
0xf7, 0xa3, 0x6a, 0x7d, 0xc5, 0x02, 0x20, 0x20, 0xa4, 0x74, 0x28, 0x97, 0xc3, 0x0a, 0xed, 0xa0, 0xa5, 0x6b, 0x36, 0xe1,
0x4e, 0xbb, 0xc8, 0x5b, 0xbd, 0xb7, 0x44, 0x93, 0xf9, 0x93, 0x58, 0x1e, 0xb0, 0x44, 0x4e, 0xd6, 0xca, 0x94, 0x0b
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/*********************************************************************************\
* Compact form for attributes and clusters
*
* Generated content, do not edit
\*********************************************************************************/
#include <stddef.h>
#include <stdint.h>
typedef struct {
uint16_t id;
const char* name;
} matter_opcode_t;
const matter_opcode_t matter_OpCodes[] = {
{ 0x0000, "MsgCounterSyncReq" },
{ 0x0001, "MsgCounterSyncRsp" },
{ 0x0010, "MRP_Standalone_Acknowledgement" },
{ 0x0020, "PBKDFParamRequest" },
{ 0x0021, "PBKDFParamResponse" },
{ 0x0022, "PASE_Pake1" },
{ 0x0023, "PASE_Pake2" },
{ 0x0024, "PASE_Pake3" },
{ 0x0030, "CASE_Sigma1" },
{ 0x0031, "CASE_Sigma2" },
{ 0x0032, "CASE_Sigma3" },
{ 0x0033, "CASE_Sigma2_Resume" },
{ 0x0040, "StatusReport" },
{ 0xFFFF, NULL },
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
{
"name": "Berry Matter protocol implementation",
"version": "0.1",
"description": "Implementation of the Matter protocol specification in Berry for Tasmota, acting as an end-device over Wifi",
"license": "MIT",
"homepage": "https://github.com/arendst/Tasmota",
"frameworks": "arduino",
"platforms": "espressif32",
"authors":
{
"name": "Stephan Hadinger",
"maintainer": true
},
"build": {
"flags": [ "-I$PROJECT_DIR/include", "-includetasmota_options.h" ]
}
}

View File

@ -0,0 +1,2 @@
# empty module
# allows stand-alone `import path`

View File

@ -0,0 +1,86 @@
#! ../berry/berry -s -g
#
# Berry solidify files
#
# `../berry/berry -s -g`
import os
import global
import solidify
import string
import re
import sys
sys.path().push('src/embedded') # allow to import from src/embedded
# globals that need to exist to make compilation succeed
var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,udp,"
"lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs,"
"lv_wifi_bars_icon,lv_wifi_bars,"
"_lvgl,"
"int64"
for g:string.split(globs, ",")
global.(g) = nil
end
var prefix_dir = "src/embedded/"
var prefix_out = "src/solidify/"
def clean_directory(dir)
var file_list = os.listdir(dir)
for f : file_list
if f[0] == '.' continue end # ignore files starting with `.`
os.remove(dir + f)
end
end
var pattern = "#@\\s*solidify:([A-Za-z0-9_.,]+)"
def parse_file(fname, prefix_out)
print("Parsing: ", fname)
var f = open(prefix_dir + fname)
var src = f.read()
f.close()
# try to compile
var compiled = compile(src)
compiled() # run the compile code to instanciate the classes and modules
# output solidified
var fname_h = string.split(fname, '.be')[0] + '.h' # take whatever is before the first '.be'
var fout = open(prefix_out + "solidified_" + fname_h, "w")
fout.write(string.format("/* Solidification of %s */\n", fname_h))
fout.write("/********************************************************************\\\n")
fout.write("* Generated code, don't edit *\n")
fout.write("\\********************************************************************/\n")
fout.write('#include "be_constobj.h"\n')
var directives = re.searchall(pattern, src)
# print(directives)
for directive : directives
var object_list = string.split(directive[1], ',')
var object_name = object_list[0]
var weak = (object_list.find('weak') != nil) # do we solidify with weak strings?
var o = global
var cl_name = nil
var obj_name = nil
for subname : string.split(object_name, '.')
o = o.(subname)
cl_name = obj_name
obj_name = subname
end
solidify.dump(o, weak, fout, cl_name)
end
fout.write("/********************************************************************/\n")
fout.write("/* End of solidification */\n")
fout.close()
end
clean_directory(prefix_out)
var src_file_list = os.listdir(prefix_dir)
for src_file : src_file_list
if src_file[0] == '.' continue end
parse_file(src_file, prefix_out)
end

View File

@ -0,0 +1,266 @@
/*
be_matter_counter.cpp - implements Matter counters for message replay prevention
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_Counter - Support for 32 bits counter with history window
*
* This is used in Matter to detect collision and replay of packets
* See section "4.5. Message Counters"
*******************************************************************/
#include <bitset>
#include "be_constobj.h"
#include "be_mapping.h"
#include "be_mem.h"
#include "esp_random.h"
#define MESSAGE_COUNTER_WINDOW_SIZE 32
typedef struct {
uint32_t counter; // value of the counter
std::bitset<MESSAGE_COUNTER_WINDOW_SIZE> window;
} matter_counter_t;
/*
* Initialize a local message counter with random value between [1, 2^28]. This increases the difficulty of traffic analysis
* attacks by making it harder to determine how long a particular session has been open. The initial counter is always 1 or
* higher to guarantee first message is always greater than initial peer counter set to 0.
*/
static void mc_randomize(matter_counter_t *c) {
// pick a random one in range 0..2^28
esp_fill_random(&c->counter, sizeof(c->counter));
c->counter = c->counter & 0x0FFFFFFF; // keep only 28 bits
if (c->counter == 0) { c->counter = 1; } // unfortunate event that the random generates `0`
c->window.reset();
}
// `Matter_Counter([counter:int]) -> instance(Matter_Counter)`
//
// Creates a new monotonic counter for sending or receiving
// If value is `0` or absent, a random counter is generated in the range 1..2^28
static void* mc_init(bvm *vm, int32_t val) {
matter_counter_t *c = (matter_counter_t*)be_malloc(vm, sizeof(matter_counter_t));
c->counter = val;
c->window.reset(); // reset the window
return c;
}
BE_FUNC_CTYPE_DECLARE(mc_init, "+_p", "@[i]")
static void mc_deinit(bvm *vm, matter_counter_t *c) {
be_free(vm, c, sizeof(matter_counter_t));
}
BE_FUNC_CTYPE_DECLARE(mc_deinit, "", "@.")
static void mc_reset(matter_counter_t *c, int32_t val) {
c->counter = val;
c->window.reset();
}
BE_FUNC_CTYPE_DECLARE(mc_reset, "", ".[i]")
int32_t mc_val(matter_counter_t *c) {
return c->counter;
}
BE_FUNC_CTYPE_DECLARE(mc_val, "i", ".")
int32_t mc_next(matter_counter_t *c) {
if (c->counter == 0) { mc_randomize(c); }
c->counter++;
c->window <<= 1;
if (c->counter == 0) {
c->counter++;
c->window <<= 1;
}
return c->counter;
}
BE_FUNC_CTYPE_DECLARE(mc_next, "i", ".")
// validate if the value is acceptable
//
// strict_mode is used for encrypted messages: roll-over is not permitted
// otherwise roll-over is permitted and counter in the past
// (outside of window) is allowed
//
// return `true` if ok, `false` if rejected
int32_t mc_validate(matter_counter_t *c, uint32_t new_val, bbool strict_mode) {
if (new_val == c->counter) { return bfalse; } // simple case of a collision of the last message
if (c->counter == 0) { // first message received, accept any value
c->counter = new_val;
c->window.reset();
return btrue;
}
if (new_val > c->counter) { // counter is in the future, same handling for both modes
if (new_val - c->counter > MESSAGE_COUNTER_WINDOW_SIZE) {
c->window.reset(); // no index is in the window anymore, clear all
} else {
c->window <<= new_val - c->counter;
c->window[new_val - c->counter - 1] = true; // mark previous val
// adjust window
}
c->counter = new_val;
return btrue;
} else { // here: new_val < c->counter
// are we in the window?
uint32_t gap = c->counter - new_val;
if (gap <= 32) {
if (c->window[gap-1]) {
return false; // reject because already seen
} else {
c->window[gap-1] = btrue;
return true;
}
} else {
// in the past and out of the window (we ignore roll-over to simplify)
if (strict_mode) {
return bfalse;
} else {
c->counter = new_val;
c->window.reset();
return btrue;
}
}
}
}
BE_FUNC_CTYPE_DECLARE(mc_validate, "b", ".ib")
static int mc_tostring(bvm *vm) {
be_getmember(vm, 1, "_p");
matter_counter_t *c = (matter_counter_t*) be_tocomptr(vm, -1);
if (c->counter != 0) {
be_pushstring(vm, "[");
for (uint32_t i = MESSAGE_COUNTER_WINDOW_SIZE; i > 0; i--) {
be_pushint(vm, c->window[i-1]);
be_toescape(vm, -1, 'x'); /* escape string */
be_strconcat(vm, -2);
be_pop(vm, 1);
}
be_pushstring(vm, "]");
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushint(vm, c->counter);
be_toescape(vm, -1, 'x'); /* escape string */
be_strconcat(vm, -2);
be_pop(vm, 1);
} else {
be_pushstring(vm, "[]-");
}
be_return(vm);
}
#include "be_fixed_be_class_Matter_Counter.h"
/* @const_object_info_begin
class be_class_Matter_Counter (scope: global, name: Matter_Counter) {
_p, var
init, ctype_func(mc_init)
deinit, ctype_func(mc_deinit)
reset, ctype_func(mc_reset)
tostring, func(mc_tostring)
val, ctype_func(mc_val)
next, ctype_func(mc_next)
validate, ctype_func(mc_validate)
}
@const_object_info_end */
/*
# Unit tests
import matter
var c = matter.Counter(100)
assert(str(c) == '[00000000000000000000000000000000]100')
assert(c.val() == 100)
assert(c.next() == 101)
assert(c.val() == 101)
assert(str(c) == '[00000000000000000000000000000000]101')
c.reset(101)
assert(!c.validate(101, true))
assert(str(c) == '[00000000000000000000000000000000]101')
c.reset(101)
assert(c.validate(100, true))
assert(str(c) == '[00000000000000000000000000000001]101')
assert(!c.validate(100, true))
assert(str(c) == '[00000000000000000000000000000001]101')
c.reset(101)
assert(c.validate(100, false))
assert(str(c) == '[00000000000000000000000000000001]101')
assert(!c.validate(100, false))
assert(str(c) == '[00000000000000000000000000000001]101')
c.reset(128)
assert(c.validate(96, true))
assert(str(c) == '[10000000000000000000000000000000]128')
assert(!c.validate(95, true))
assert(str(c) == '[10000000000000000000000000000000]128')
c.reset(128)
assert(c.validate(96, false))
assert(str(c) == '[10000000000000000000000000000000]128')
assert(c.validate(95, false))
assert(str(c) == '[00000000000000000000000000000000]95')
c.reset(100)
# set the context as in the documentation
assert(c.validate(99, true))
assert(c.validate(96, true))
assert(c.validate(70, true))
assert(str(c) == '[00100000000000000000000000001001]100')
assert(c.validate(97, true))
assert(str(c) == '[00100000000000000000000000001101]100')
assert(!c.validate(100, true))
assert(!c.validate(99, true))
assert(!c.validate(97, true))
assert(!c.validate(96, true))
assert(!c.validate(70, true))
assert(str(c) == '[00100000000000000000000000001101]100') # unchanged
assert(c.validate(101, true))
assert(str(c) == '[01000000000000000000000000011011]101')
assert(c.validate(103, true))
assert(str(c) == '[00000000000000000000000001101110]103')
assert(!c.validate(70, true))
assert(c.validate(200, true))
assert(str(c) == '[00000000000000000000000000000000]200')
### counters for outgoing messages
c.reset()
assert(c.val() == 0)
*/

View File

@ -0,0 +1,270 @@
/*
be_matter_module.c - implements the high level `matter` Berry module
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 global module
*
*******************************************************************/
#include "be_constobj.h"
#include "be_mapping.h"
#include "be_matter_qrcode_min_js.h"
// Matter logo
static const uint8_t MATTER_LOGO[] =
"<svg style='vertical-align:middle;' width='24' height='24' xmlns='http://www.w3.org/2000/svg' viewBox='100 100 240 240'>"
"<defs><style>.cls-1{fill:none}.cls-2{fill:#FFFFFF;}</style></defs><rect class='cls-1' "
"width='420' height='420'/><path class='cls-2' d='"
"M167,156.88a71,71,0,0,0,32.1,14.73v-62.8l12.79-7.38,12.78,7.38v62.8a71.09,71.09,0,0,0,32.11-14.73"
"L280,170.31a96.92,96.92,0,0,1-136.33,0Zm28.22,160.37A96.92,96.92,0,0,0,127,199.19v26.87a71.06,"
"71.06,0,0,1,28.82,20.43l-54.39,31.4v14.77L114.22,300l54.38-31.4a71,71,0,0,1,3.29,35.17Zm101.5-"
"118.06a96.93,96.93,0,0,0-68.16,118.06l23.27-13.44a71.1,71.1,0,0,1,3.29-35.17L309.46,300l12.78-"
"7.38V277.89l-54.39-31.4a71.13,71.13,0,0,1,28.82-20.43Z'/></svg>";
extern const bclass be_class_Matter_Counter;
extern const bclass be_class_Matter_Verhoeff;
#include "solidify/solidified_Matter_Module.h"
#include "../generate/be_matter_clusters.h"
#include "../generate/be_matter_opcodes.h"
const char* matter_get_cluster_name(uint16_t cluster) {
for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) {
if (cl->id == cluster) {
return cl->name;
}
}
return NULL;
}
BE_FUNC_CTYPE_DECLARE(matter_get_cluster_name, "s", "i")
const char* matter_get_opcode_name(uint16_t opcode) {
for (const matter_opcode_t * op = matter_OpCodes; op->id != 0xFFFF; op++) {
if (op->id == opcode) {
return op->name;
}
}
return NULL;
}
BE_FUNC_CTYPE_DECLARE(matter_get_opcode_name, "s", "i")
const char* matter_get_attribute_name(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->name;
}
}
}
}
return NULL;
}
BE_FUNC_CTYPE_DECLARE(matter_get_attribute_name, "s", "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) {
for (const matter_command_t * cmd = cl->commands; cmd->id != 0xFFFF; cmd++) {
if (cmd->id == command) {
return cmd->name;
}
}
}
}
return NULL;
}
BE_FUNC_CTYPE_DECLARE(matter_get_command_name, "s", "ii")
#include "solidify/solidified_Matter_inspect.h"
extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference
#include "solidify/solidified_Matter_TLV.h"
#include "solidify/solidified_Matter_IM_Data.h"
#include "solidify/solidified_Matter_UDPServer.h"
#include "solidify/solidified_Matter_Session.h"
#include "solidify/solidified_Matter_Commissioning_Data.h"
#include "solidify/solidified_Matter_Commissioning.h"
#include "solidify/solidified_Matter_Message.h"
#include "solidify/solidified_Matter_MessageHandler.h"
#include "solidify/solidified_Matter_IM.h"
#include "solidify/solidified_Matter_Plugin.h"
#include "solidify/solidified_Matter_Base38.h"
#include "solidify/solidified_Matter_UI.h"
#include "solidify/solidified_Matter_Device.h"
#include "../generate/be_matter_certs.h"
#include "solidify/solidified_Matter_Plugin_core.h"
#include "solidify/solidified_Matter_Plugin_Relay.h"
/*********************************************************************************************\
* Get a bytes() object of the certificate DAC/PAI_Cert
\*********************************************************************************************/
static int matter_return_static_bytes(bvm *vm, const uint8* addr, size_t len) {
be_getbuiltin(vm, "bytes");
be_pushcomptr(vm, addr);
be_pushint(vm, - len);
be_call(vm, 2);
be_pop(vm, 2);
be_return(vm);
}
static int matter_PAI_Cert_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_Cert_FFF1, sizeof(kDevelopmentPAI_Cert_FFF1)); }
static int matter_PAI_Pub_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_PublicKey_FFF1, sizeof(kDevelopmentPAI_PublicKey_FFF1)); }
static int matter_PAI_Priv_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_PrivateKey_FFF1, sizeof(kDevelopmentPAI_PrivateKey_FFF1)); }
static int matter_DAC_Cert_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_Cert_FFF1_8000, sizeof(kDevelopmentDAC_Cert_FFF1_8000)); }
static int matter_DAC_Pub_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_PublicKey_FFF1_8000, sizeof(kDevelopmentDAC_PublicKey_FFF1_8000)); }
static int matter_DAC_Priv_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_PrivateKey_FFF1_8000, sizeof(kDevelopmentDAC_PrivateKey_FFF1_8000)); }
static int matter_CD_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kCdForAllExamples, sizeof(kCdForAllExamples)); }
#include "be_fixed_matter.h"
/* @const_object_info_begin
module matter (scope: global) {
_LOGO, comptr(MATTER_LOGO)
_QRCODE_MINJS, comptr(QRCODE_MINJS)
MATTER_OPTION, int(151) // SetOption151 enables Matter
Verhoeff, class(be_class_Matter_Verhoeff)
Counter, class(be_class_Matter_Counter)
setmember, closure(matter_setmember_closure)
member, closure(matter_member_closure)
get_cluster_name, ctype_func(matter_get_cluster_name)
get_attribute_name, ctype_func(matter_get_attribute_name)
get_command_name, ctype_func(matter_get_command_name)
get_opcode_name, ctype_func(matter_get_opcode_name)
TLV, class(be_class_Matter_TLV)
sort, closure(matter_sort_closure)
inspect, closure(matter_inspect_closure)
// Status codes
SUCCESS, int(0x00)
FAILURE, int(0x01)
INVALID_SUBSCRIPTION, int(0x7D)
UNSUPPORTED_ACCESS, int(0x7E)
UNSUPPORTED_ENDPOINT, int(0x7F)
INVALID_ACTION, int(0x80)
UNSUPPORTED_COMMAND, int(0x81)
INVALID_COMMAND, int(0x85)
UNSUPPORTED_ATTRIBUTE, int(0x86)
CONSTRAINT_ERROR, int(0x87)
UNSUPPORTED_WRITE, int(0x88)
RESOURCE_EXHAUSTED, int(0x89)
NOT_FOUND, int(0x8B)
UNREPORTABLE_ATTRIBUTE, int(0x8C)
INVALID_DATA_TYPE, int(0x8D)
UNSUPPORTED_READ, int(0x8F)
DATA_VERSION_MISMATCH, int(0x92)
TIMEOUT, int(0x94)
UNSUPPORTED_NODE, int(0x9B)
BUSY, int(0x9C)
UNSUPPORTED_CLUSTER, int(0xC3)
NO_UPSTREAM_SUBSCRIP­TION, int(0xC5)
NEEDS_TIMED_INTERACTION, int(0xC6)
UNSUPPORTED_EVENT, int(0xC7)
PATHS_EXHAUSTED, int(0xC8)
TIMED_REQUEST_MISMATCH, int(0xC9)
FAILSAFE_REQUIRED, int(0xCA)
// Matter_Data_IM classes
AttributePathIB, class(be_class_Matter_AttributePathIB)
ClusterPathIB, class(be_class_Matter_ClusterPathIB)
DataVersionFilterIB, class(be_class_Matter_DataVersionFilterIB)
AttributeDataIB, class(be_class_Matter_AttributeDataIB)
AttributeReportIB, class(be_class_Matter_AttributeReportIB)
EventFilterIB, class(be_class_Matter_EventFilterIB)
EventPathIB, class(be_class_Matter_EventPathIB)
EventDataIB, class(be_class_Matter_EventDataIB)
EventReportIB, class(be_class_Matter_EventReportIB)
CommandPathIB, class(be_class_Matter_CommandPathIB)
CommandDataIB, class(be_class_Matter_CommandDataIB)
InvokeResponseIB, class(be_class_Matter_InvokeResponseIB)
CommandStatusIB, class(be_class_Matter_CommandStatusIB)
EventStatusIB, class(be_class_Matter_EventStatusIB)
AttributeStatusIB, class(be_class_Matter_AttributeStatusIB)
StatusIB, class(be_class_Matter_StatusIB)
StatusResponseMessage, class(be_class_Matter_StatusResponseMessage)
ReadRequestMessage, class(be_class_Matter_ReadRequestMessage)
ReportDataMessage, class(be_class_Matter_ReportDataMessage)
SubscribeRequestMessage, class(be_class_Matter_SubscribeRequestMessage)
SubscribeResponseMessage, class(be_class_Matter_SubscribeResponseMessage)
WriteRequestMessage, class(be_class_Matter_WriteRequestMessage)
WriteResponseMessage, class(be_class_Matter_WriteResponseMessage)
TimedRequestMessage, class(be_class_Matter_TimedRequestMessage)
InvokeRequestMessage, class(be_class_Matter_InvokeRequestMessage)
InvokeResponseMessage, class(be_class_Matter_InvokeResponseMessage)
// Matter Commisioning messages
PBKDFParamRequest, class(be_class_Matter_PBKDFParamRequest)
PBKDFParamResponse, class(be_class_Matter_PBKDFParamResponse)
Pake1, class(be_class_Matter_Pake1)
Pake2, class(be_class_Matter_Pake2)
Pake3, class(be_class_Matter_Pake3)
Sigma1, class(be_class_Matter_Sigma1)
Sigma2, class(be_class_Matter_Sigma2)
Sigma2Resume, class(be_class_Matter_Sigma2Resume)
Sigma3, class(be_class_Matter_Sigma3)
Commisioning_Context, class(be_class_Matter_Commisioning_Context)
// UDP Server
UDPPacket_sent, class(be_class_Matter_UDPPacket_sent)
UDPServer, class(be_class_Matter_UDPServer)
// Sessions
Session, class(be_class_Matter_Session)
Session_Store, class(be_class_Matter_Session_Store)
// Message Handler
Frame, class(be_class_Matter_Frame)
MessageHandler, class(be_class_Matter_MessageHandler)
// Interation Model
Response_container, class(be_class_Matter_Response_container)
IM, class(be_class_Matter_IM)
Plugin_core, class(be_class_Matter_Plugin_core)
UI, class(be_class_Matter_UI)
// Base38 for QR Code
Base38, class(be_class_Matter_Base38)
// Matter Device core class
Device, class(be_class_Matter_Device)
// credentials from example
PAI_Cert_FFF1, func(matter_PAI_Cert_FFF1)
PAI_Pub_FFF1, func(matter_PAI_Pub_FFF1)
PAI_Priv_FFF1, func(matter_PAI_Priv_FFF1)
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
// 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)
}
@const_object_info_end */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,105 @@
/*
be_matter_verhoeff.cpp - implements the Verhoeff algorithm to compute a checksum digit for QR Code
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/>.
*/
#include <string.h>
#include <stdbool.h>
#include "be_constobj.h"
#include "be_mapping.h"
// code inspired from https://www.programmingalgorithms.com/algorithm/verhoeff-algorithm/c/
static const int8_t _multiplicationTable[10][10] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 1, 2, 3, 4, 0, 6, 7, 8, 9, 5 },
{ 2, 3, 4, 0, 1, 7, 8, 9, 5, 6 },
{ 3, 4, 0, 1, 2, 8, 9, 5, 6, 7 },
{ 4, 0, 1, 2, 3, 9, 5, 6, 7, 8 },
{ 5, 9, 8, 7, 6, 0, 4, 3, 2, 1 },
{ 6, 5, 9, 8, 7, 1, 0, 4, 3, 2 },
{ 7, 6, 5, 9, 8, 2, 1, 0, 4, 3 },
{ 8, 7, 6, 5, 9, 3, 2, 1, 0, 4 },
{ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }
};
static const int8_t _permutationTable[10][10] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 1, 5, 7, 6, 2, 8, 3, 0, 9, 4 },
{ 5, 8, 0, 3, 7, 9, 6, 1, 4, 2 },
{ 8, 9, 1, 6, 0, 4, 3, 5, 2, 7 },
{ 9, 4, 5, 3, 1, 2, 6, 8, 7, 0 },
{ 4, 2, 8, 6, 5, 7, 3, 9, 0, 1 },
{ 2, 7, 9, 3, 8, 0, 6, 4, 1, 5 },
{ 7, 0, 4, 6, 9, 1, 3, 2, 5, 8 }
};
static const int8_t _inverseTable[10] = { 0, 4, 3, 2, 1, 5, 6, 7, 8, 9 };
static char ret_digit[] = "0"; // used as a placeholder to return a single digit string
const char* vh_checksum(const char* number) {
int32_t c = 0;
int32_t len = strlen(number);
for (int32_t i = 0; i < len; ++i) {
int8_t digit = number[len - i - 1] - '0';
if (digit < 0) { digit = 0; }
if (digit > 9) { digit = 9; }
c = _multiplicationTable[c][_permutationTable[((i + 1) % 8)][digit]];
}
ret_digit[0] = _inverseTable[c] + '0';
return ret_digit;
}
BE_FUNC_CTYPE_DECLARE(vh_checksum, "s", "s")
static bbool vh_validate(char* number) {
int32_t c = 0;
int32_t len = strlen(number);
for (int32_t i = 0; i < len; ++i) {
int8_t digit = number[len - i - 1] - '0';
if (digit < 0) { digit = 0; }
if (digit > 9) { digit = 9; }
c = _multiplicationTable[c][_permutationTable[(i % 8)][digit]];
}
return c == 0;
}
BE_FUNC_CTYPE_DECLARE(vh_validate, "b", "s")
#include "be_fixed_be_class_Matter_Verhoeff.h"
/* @const_object_info_begin
class be_class_Matter_Verhoeff (scope: global, name: Matter_Verhoeff) {
checksum, static_ctype_func(vh_checksum)
validate, static_ctype_func(vh_validate)
}
@const_object_info_end */
/*
# Unit tests
import matter
assert(matter.Verhoeff.checksum("236") == "3")
assert(matter.Verhoeff.validate("236"))
assert(matter.Verhoeff.checksum("58564") == "9")
assert(matter.Verhoeff.validate("585649"))
*/

View File

@ -0,0 +1,8 @@
// force include of module by including this file
#ifndef __BERRY_MATTER__
#define __BERRY_MATTER__
#endif // __BERRY_MATTER__

View File

@ -0,0 +1,71 @@
#
# Matter_Base38.be - suppport for Base38 encoding which is used in QR Codes
#
# 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_Base38,weak
class Matter_Base38
static def encode(raw)
# encodes b38 (mutates `b`)
def b38_enc(v, l)
import string
var ENCODE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-."
var i = 0
var ret = ""
while i < l
ret += ENCODE[v % 38]
v = v / 38
i += 1
end
return ret
end
var idx = 0
var sz = size(raw)
var out = ""
while idx < sz
var val
if idx + 2 < sz
# encode 3 bytes
val = raw[idx] | (raw[idx+1] << 8) | (raw[idx+2] << 16)
out += b38_enc(val, 5)
idx += 3
elif idx + 1 < sz
# encode 2 bytes
val = raw[idx] | (raw[idx+1] << 8)
out += b38_enc(val, 4)
idx += 2
else
# encode 1 byte
val = raw[idx]
out += b38_enc(val, 2)
idx += 1
end
end
return out
end
end
matter.Base38 = Matter_Base38
#-
-#

View File

@ -0,0 +1,632 @@
#
# Matter_Commissioning.be - suppport for Matter Commissioning process
#
# 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_Commisioning_Context,weak
#################################################################################
# Class Matter_Commisioning_Context
#################################################################################
class Matter_Commisioning_Context
# static Matter_Context_Prefix = "Matter PAKE V1 Commissioning" # spec is wrong
static var Matter_Context_Prefix = "CHIP PAKE V1 Commissioning" # from CHIP code
static var SEKeys_Info = "SessionKeys"
static var S2K_Info = "Sigma2"
static var S3K_Info = "Sigma3"
static var TBEData2_Nonce = "NCASE_Sigma2N"
static var TBEData3_Nonce = "NCASE_Sigma3N"
var responder # reference to the caller, sending packets
var device # root device object
var spake
var future_initiator_session_id
var future_local_session_id
# used by TT hash
var PBKDFParamRequest, PBKDFParamResponse
# PAKE
var y # 32 bytes random known only by verifier
var pA, pB, cA, cB
var Ke
# CASE
var ResponderEph_priv, ResponderEph_pub
var initiatorEph_pub
# Session data
var session_timestamp
var I2RKey, R2IKey, AttestationChallenge
# is commissioning window open
var window_open
def init(responder)
import crypto
self.responder = responder
self.device = responder.device
# generate y once
self.y = crypto.random(32)
self.window_open = true # auto-commissioning for now
end
def process_incoming(msg, remote_ip, remote_port)
#
if !self.window_open
tasmota.log("MTR: commissioning not open", 2)
return false
end
tasmota.log("MTR: received message " + matter.inspect(msg), 3)
if msg.opcode == 0x20
return self.parse_PBKDFParamRequest(msg, remote_ip, remote_port)
elif msg.opcode == 0x22
return self.parse_Pake1(msg, remote_ip, remote_port)
elif msg.opcode == 0x24
return self.parse_Pake3(msg, remote_ip, remote_port)
elif msg.opcode == 0x30
return self.parse_Sigma1(msg, remote_ip, remote_port)
elif msg.opcode == 0x32
return self.parse_Sigma3(msg, remote_ip, remote_port)
end
return false
end
def parse_PBKDFParamRequest(msg, addr, port)
import crypto
# sanity checks
if msg.opcode != 0x20 || msg.local_session_id != 0 || msg.protocol_id != 0
raise "protocol_error", "invalid PBKDFParamRequest message"
end
var pbkdfparamreq = matter.PBKDFParamRequest().parse(msg.raw, msg.app_payload_idx)
msg.session.set_mode(matter.Session.__PASE)
self.PBKDFParamRequest = msg.raw[msg.app_payload_idx..]
# sanity check for PBKDFParamRequest
if pbkdfparamreq.passcodeId != 0 raise "protocol_error", "non-zero passcode id" end
# record the initiator_session_id
self.future_initiator_session_id = pbkdfparamreq.initiator_session_id
self.future_local_session_id = self.device.sessions.gen_local_session_id()
# prepare response
var pbkdfparamresp = matter.PBKDFParamResponse()
pbkdfparamresp.initiatorRandom = pbkdfparamreq.initiatorRandom
# generate 32 bytes random
pbkdfparamresp.responderRandom = crypto.random(32)
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)
var pbkdfparamresp_raw = pbkdfparamresp.encode()
tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 3)
self.PBKDFParamResponse = pbkdfparamresp_raw
var resp = msg.build_response(0x21 #-PBKDR Response-#, true)
var raw = resp.encode(pbkdfparamresp_raw)
self.responder.send_response(raw, addr, port, resp.message_counter)
end
def parse_Pake1(msg, addr, port)
import crypto
# sanity checks
if msg.opcode != 0x22 || msg.local_session_id != 0 || msg.protocol_id != 0
raise "protocol_error", "invalid Pake1 message"
end
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: spake: " + matter.inspect(self.spake), 3)
# 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)
# 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)
var context = crypto.SHA256()
context.update(bytes().fromstring(self.Matter_Context_Prefix))
context.update(self.PBKDFParamRequest)
context.update(self.PBKDFParamResponse)
var context_hash = context.out()
tasmota.log("MTR: Context=" + context_hash.tohex(), 3)
# add pA
self.spake.pA = self.pA
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: Kmain =" + self.spake.Kmain.tohex(), 3)
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)
self.cB = self.spake.cB
self.Ke = self.spake.Ke
tasmota.log("MTR: cB=" + self.cB.tohex(), 3)
var pake2 = matter.Pake2()
pake2.pB = self.pB
pake2.cB = self.cB
tasmota.log("MTR: pake2: " + matter.inspect(pake2), 3)
var pake2_raw = pake2.encode()
tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 3)
# now package the response message
var resp = msg.build_response(0x23 #-pake-2-#, true) # no reliable flag
var raw = resp.encode(pake2_raw)
self.responder.send_response(raw, addr, port, resp.message_counter)
end
def parse_Pake3(msg, addr, port)
import crypto
# sanity checks
if msg.opcode != 0x24 || msg.local_session_id != 0 || msg.protocol_id != 0
raise "protocol_error", "invalid Pake3 message"
end
var pake3 = matter.Pake3().parse(msg.raw, msg.app_payload_idx)
self.cA = pake3.cA
tasmota.log("MTR: received cA=" + self.cA.tohex(), 3)
# check the value against computed
if self.cA != self.spake.cA raise "protocol_error", "invalid cA received" end
# send PakeFinished and compute session key
self.session_timestamp = tasmota.rtc()['utc']
var session_keys = crypto.HKDF_SHA256().derive(self.Ke, bytes(), bytes().fromstring(self.SEKeys_Info), 48)
self.I2RKey = session_keys[0..15]
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)
# now package the response message
var resp = msg.build_response(0x40 #-StatusReport-#, false) # no reliable flag
var status_raw = bytes()
status_raw.add(0x00, 2) # GeneralCode = SUCCESS
status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL)
status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS)
var raw = resp.encode(status_raw)
self.responder.send_response(raw, addr, port, nil)
self.responder.add_session(self.future_local_session_id, self.future_initiator_session_id, self.I2RKey, self.R2IKey, self.AttestationChallenge, self.session_timestamp)
end
def find_session_by_destination_id(destinationId, initiatorRandom)
import crypto
# Validate Sigma1 Destination ID, p.162
# traverse all existing sessions
tasmota.log("MTR: SEARCHING: destinationId=" + destinationId.tohex(), 3)
for session:self.device.sessions.sessions
if session.noc == nil || session.fabric == nil || session.deviceid == nil continue end
# compute candidateDestinationId, Section 4.13.2.4.1, “Destination Identifier”
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)
var h = crypto.HMAC_SHA256(key)
h.update(destinationMessage)
var candidateDestinationId = h.out()
tasmota.log("MTR: SIGMA1: candidateDestinationId=" + candidateDestinationId.tohex(), 3)
if candidateDestinationId == destinationId
return session
end
end
return nil
end
def parse_Sigma1(msg, addr, port)
import crypto
# sanity checks
if msg.opcode != 0x30 || msg.local_session_id != 0 || msg.protocol_id != 0
raise "protocol_error", "invalid Pake1 message"
end
var sigma1 = matter.Sigma1().parse(msg.raw, msg.app_payload_idx)
self.initiatorEph_pub = sigma1.initiatorEphPubKey
# find session
var session = self.find_session_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom)
if session == nil raise "valuer_error", "StatusReport(GeneralCode: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: NO_SHARED_TRUST_ROOTS)" end
session.source_node_id = msg.source_node_id
session.set_mode(matter.Session.__CASE)
if msg.session
self.device.sessions.remove_session(msg.session) # drop the temporary session that was created
end
msg.session = session
session._future_initiator_session_id = sigma1.initiator_session_id # update initiator_session_id
session._future_local_session_id = self.device.sessions.gen_local_session_id()
self.future_local_session_id = session._future_local_session_id
# Check that it's a resumption
if sigma1.resumptionID != nil && sigma1.initiatorResumeMIC != nil &&
session.shared_secret != nil
# Resumption p.169
var s1rk_salt = sigma1.initiatorRandom + sigma1.resumptionID
var s1rk_info = bytes().fromstring("Sigma1_Resume")
var s1rk = crypto.HKDF_SHA256().derive(session.shared_secret, s1rk_salt, s1rk_info, 16)
var Resume1MIC_Nonce = bytes().fromstring("NCASE_SigmaR1")
var encrypted = sigma1.initiatorResumeMIC[0..-17]
var tag = sigma1.initiatorResumeMIC[-16..]
var ec = crypto.AES_CCM(s1rk, Resume1MIC_Nonce, bytes(), size(encrypted), 16)
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)
if tag == decrypted_tag
# Generate and Send Sigma2_Resume
session.resumption_id = crypto.random(16) # generate a new resumption id
# compute S2RK
var s2rk_info = bytes().fromstring("Sigma2_Resume") + session.resumption_id
var s2rk_salt = sigma1.initiatorRandom + sigma1.resumptionID
var s2rk = crypto.HKDF_SHA256().derive(session.shared_secret, s2rk_salt, s2rk_info, 16)
# compute Resume2MIC
var aes = crypto.AES_CCM(s2rk, bytes().fromstring("NCASE_SigmaR2"), bytes(), 0, 16)
var Resume2MIC = aes.tag()
var sigma2resume = matter.Sigma2Resume()
sigma2resume.resumptionID = session.resumption_id
sigma2resume.responderSessionID = session._future_local_session_id
sigma2resume.sigma2ResumeMIC = Resume2MIC
# # compute session key, p.178
var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#,
sigma1.initiatorRandom + sigma1.resumptionID #- salt -#,
bytes().fromstring("SessionResumptionKeys") #- info -#,
48)
var i2r = session_keys[0..15]
var r2i = session_keys[16..31]
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)
var sigma2resume_raw = sigma2resume.encode()
session._Msg1 = nil
tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 3)
# now package the response message
var resp = msg.build_response(0x33 #-sigma-2-resume-#, true)
var raw = resp.encode(sigma2resume_raw)
self.responder.send_response(raw, addr, port, resp.message_counter)
session.close()
session.set_keys(i2r, r2i, ac, session_timestamp)
session.set_persist(true) # keep session on flash
session.set_no_expiration() # never expire
session.save()
return true
else
sigma1.resumptionID = nil
# fall through normal sigma1 (non-resumption)
end
end
if sigma1.resumptionID == nil || sigma1.initiatorResumeMIC == nil
# Compute Sigma2, p.162
session.resumption_id = crypto.random(16)
self.ResponderEph_priv = crypto.random(32)
self.ResponderEph_pub = crypto.EC_P256().public_key(self.ResponderEph_priv)
var responderRandom = crypto.random(32)
session.shared_secret = crypto.EC_P256().shared_key(self.ResponderEph_priv, sigma1.initiatorEphPubKey)
var sigma2_tbsdata = matter.TLV.Matter_TLV_struct()
sigma2_tbsdata.add_TLV(1, matter.TLV.B2, session.get_noc())
sigma2_tbsdata.add_TLV(2, matter.TLV.B2, session.get_icac())
sigma2_tbsdata.add_TLV(3, matter.TLV.B2, self.ResponderEph_pub)
sigma2_tbsdata.add_TLV(4, matter.TLV.B2, sigma1.initiatorEphPubKey)
var TBSData2Signature = crypto.EC_P256().ecdsa_sign_sha256(session.get_pk(), sigma2_tbsdata.encode())
var sigma2_tbedata = matter.TLV.Matter_TLV_struct()
sigma2_tbedata.add_TLV(1, matter.TLV.B2, session.get_noc())
sigma2_tbedata.add_TLV(2, matter.TLV.B2, session.get_icac())
sigma2_tbedata.add_TLV(3, matter.TLV.B2, TBSData2Signature)
sigma2_tbedata.add_TLV(4, matter.TLV.B2, session.resumption_id)
# compute TranscriptHash = Crypto_Hash(message = Msg1)
tasmota.log("****************************************", 3)
session._Msg1 = sigma1.Msg1
tasmota.log("MTR: * MSG1 = " + session._Msg1.tohex(), 3)
var TranscriptHash = crypto.SHA256().update(session._Msg1).out()
# Compute S2K, p.175
var s2k_info = bytes().fromstring(self.S2K_Info)
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)
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)
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)
var sigma2_raw = sigma2.encode()
session._Msg2 = sigma2_raw
tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 3)
# now package the response message
var resp = msg.build_response(0x31 #-sigma-2-#, true) # no reliable flag
var raw = resp.encode(sigma2_raw)
self.responder.send_response(raw, addr, port, resp.message_counter)
return true
end
return true
end
def parse_Sigma3(msg, addr, port)
import crypto
# sanity checks
if msg.opcode != 0x32 || msg.local_session_id != 0 || msg.protocol_id != 0
raise "protocol_error", "invalid Pake1 message"
end
var session = msg.session
var sigma3 = matter.Sigma3().parse(msg.raw, msg.app_payload_idx)
tasmota.log("****************************************", 3)
# 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)
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)
# 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)
# decrypt
var encrypted = sigma3.TBEData3Encrypted[0..-17]
var tag = sigma3.TBEData3Encrypted[-16..]
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)
if TBETag3 != tag raise "value_error", "tag do not match" end
var TBEData3TLV = matter.TLV.parse(TBEData3)
var initiatorNOC = TBEData3TLV.findsubval(1)
var initiatorICAC = TBEData3TLV.findsubval(2)
var ec_signature = TBEData3TLV.findsubval(3)
# Success = Crypto_VerifyChain(certificates = [TBEData3.initiatorNOC, TBEData3.initiatorICAC, TrustedRCAC]), when TBEData3.initiatorICAC is present
# TODO
var initiatorNOCTLV = matter.TLV.parse(initiatorNOC)
tasmota.log("MTR: initiatorNOCTLV = " + str(initiatorNOCTLV), 3)
var initiatorNOCPubKey = initiatorNOCTLV.findsubval(9)
var initiatorNOCListDN = initiatorNOCTLV.findsub(6)
var initiatorFabricId = initiatorNOCListDN.findsubval(17)
if type(initiatorFabricId) == 'int' initiatorFabricId = int64(initiatorFabricId) end
session.peer_node_id = initiatorFabricId.tobytes()
tasmota.log("MTR: initiatorFabricId="+str(session.peer_node_id), 3)
var sigma3_tbs = matter.TLV.Matter_TLV_struct()
sigma3_tbs.add_TLV(1, matter.TLV.B1, initiatorNOC)
sigma3_tbs.add_TLV(2, matter.TLV.B1, initiatorICAC)
sigma3_tbs.add_TLV(3, matter.TLV.B1, self.initiatorEph_pub)
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)
# `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)
if !sigma3_tbs_valid raise "value_error", "sigma3_tbs does not have a valid signature" end
# All good, compute new keys
tasmota.log("MTR: Sigma3 verified, computing new keys", 3)
TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).update(sigma3.Msg3).out()
# we can now free _Msg1 and _Msg2
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)
# compute session key
var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#,
session.get_ipk_group_key() + TranscriptHash #- salt -#,
bytes().fromstring(self.SEKeys_Info) #- info -#,
48)
var i2r = session_keys[0..15]
var r2i = session_keys[16..31]
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)
# Send success status report
var resp = msg.build_response(0x40 #-StatusReport-#, true) # reliable flag
var status_raw = bytes()
status_raw.add(0x00, 2) # GeneralCode = SUCCESS
status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL)
status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS)
var raw = resp.encode(status_raw)
self.responder.send_response(raw, addr, port, resp.message_counter)
session.close()
session.set_keys(i2r, r2i, ac, session_timestamp)
session.set_persist(true) # keep session on flash
session.set_no_expiration() # never expire
session.save()
return true
end
#############################################################
# placeholder, nothing to run for now
def every_second()
end
end
matter.Commisioning_Context = Matter_Commisioning_Context
#-
# STEP 1
PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'),
'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461}
# ##########################################################################################
PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
print(matter.inspect(PBKDF_PR))
{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), 'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461}
var r = matter.PBKDFParamResponse()
r.initiatorRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00")
r.responderRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00")
r.responderSessionId = 1234
r.pbkdf_parameters_iterations = 1000
r.pbkdf_parameters_salt = bytes("deadbeef11223344deadbeef11223344")
r.SLEEPY_IDLE_INTERVAL = 100
r.SLEEPY_ACTIVE_INTERVAL = 200
bytes('15300120112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00300220112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF002503D20418')
# ##########################################################################################
var m = matter.Frame()
m.decode(bytes("0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
# 'opcode': 32
# 'local_session_id': 0
# 'protocol_id': 0
#{'dest_node_id_8': nil, 'flag_dsiz': 0, 'x_flag_r': 1, 'sec_c': 0, 'app_payload_idx': 22, 'sec_flags': 0,
#'dest_node_id_2': nil, 'x_flag_sx': 0, 'sec_p': 0, 'message_counter': 159020038, 'x_flag_v': 0, 'flags': 4,
#'vendor_id': nil, 'x_flag_i': 1, 'source_node_id': bytes('347BFD880AC81280'),
#'ack_message_counter': nil, 'raw': bytes('0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9...'),
#'exchange_id': 50015, 'opcode': 32, 'local_session_id': 0, 'x_flag_a': 0, 'flag_s': 1, 'x_flags': 5, 'sec_sesstype': 0,
#'sec_extensions': nil, 'sec_mx': 0, 'protocol_id': 0}
0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818
12:09:05.561 MTR: sending packet to '192.168.2.109:5540' 050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018
050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018
12:10:29.174 MTR: received message {
'flag_s': 1, 'flag_dsiz': 1, 'x_flag_r': 1, 'x_flag_sx': 1, 'sec_mx': 0, 'sec_flags': 0,
'dest_node_id_2': nil, 'sec_sesstype': 0, 'local_session_id': 0, 'ack_message_counter': -2014389550,
'x_flag_v': 1, 'flags': 5, 'vendor_id': 8193, 'x_flag_i': 1, 'source_node_id': bytes('96B90B530000347B'),
'app_payload_idx': 51590,
'raw': bytes('050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120...'),
'exchange_id': 0, 'opcode': 195, 'message_counter': 734557190, 'sec_p': 0, 'sec_c': 0,
'protocol_id': 12309, 'dest_node_id_8': bytes('FD880AC812800021'),
'sec_extensions': nil, 'x_flag_a': 1, 'x_flags': 95}
347BFD880AC81280
fe80::1bf1:bd1a:c5ff:818a
b8:27:eb:8b:d2:59
{'mac': 'C8:2B:96:B9:0B:53', 'ip6local': 'fe80::ca2b:96ff:feb9:b53', 'ip': '192.168.1.116'}
-#

View File

@ -0,0 +1,317 @@
#
# Matter_Commissioning_Data.be - suppport for Matter Commissioning messages structure
#
# 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_PBKDFParamRequest,weak
#@ solidify:Matter_PBKDFParamResponse,weak
#@ solidify:Matter_Pake1,weak
#@ solidify:Matter_Pake2,weak
#@ solidify:Matter_Pake3,weak
#@ solidify:Matter_Sigma1,weak
#@ solidify:Matter_Sigma2,weak
#@ solidify:Matter_Sigma2Resume,weak
#@ solidify:Matter_Sigma3,weak
#################################################################################
# class PBKDFParamRequest encaspulating pbkdfparamreq-struct (p. 151)
#################################################################################
class Matter_PBKDFParamRequest
var initiatorRandom
var initiator_session_id
var passcodeId
var hasPBKDFParameters
var SLEEPY_IDLE_INTERVAL
var SLEEPY_ACTIVE_INTERVAL
def parse(b, idx)
if idx == nil idx = 0 end
var val = matter.TLV.parse(b, idx)
self.initiatorRandom = val.getsubval(1)
self.initiator_session_id = val.getsubval(2)
self.passcodeId = val.getsubval(3)
self.hasPBKDFParameters = val.getsubval(4)
var initiatorSEDParams = val.findsub(5)
if initiatorSEDParams != nil
self.SLEEPY_IDLE_INTERVAL = initiatorSEDParams.findsubval(1)
self.SLEEPY_ACTIVE_INTERVAL = initiatorSEDParams.findsubval(2)
end
return self
end
end
matter.PBKDFParamRequest = Matter_PBKDFParamRequest
#################################################################################
# class PBKDFParamResponse encaspulating pbkdfparamresp-struct (p. 153)
#################################################################################
class Matter_PBKDFParamResponse
var initiatorRandom
var responderRandom
var responderSessionId
var pbkdf_parameters_iterations
var pbkdf_parameters_salt
var SLEEPY_IDLE_INTERVAL
var SLEEPY_ACTIVE_INTERVAL
def encode(b)
var s = matter.TLV.Matter_TLV_struct()
# initiatorRandom
s.add_TLV(1, matter.TLV.B1, self.initiatorRandom)
s.add_TLV(2, matter.TLV.B1, self.responderRandom)
s.add_TLV(3, matter.TLV.U2, self.responderSessionId)
var s_pbkdf = s.add_struct(4)
s_pbkdf.add_TLV(1, matter.TLV.U4, self.pbkdf_parameters_iterations)
s_pbkdf.add_TLV(2, matter.TLV.B1, self.pbkdf_parameters_salt)
if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil
var s2 = s.add_struct(5)
s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL)
s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL)
end
return s.encode()
end
end
matter.PBKDFParamResponse = Matter_PBKDFParamResponse
#################################################################################
# class Pake1
#################################################################################
class Matter_Pake1
var pA
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)
self.pA = val.getsubval(1)
return self
end
end
matter.Pake1 = Matter_Pake1
#################################################################################
# class Pake1
#################################################################################
class Matter_Pake2
var pB # 65 bytes
var cB # 32 bytes
def encode(b)
var s = matter.TLV.Matter_TLV_struct()
#
s.add_TLV(1, matter.TLV.B1, self.pB)
s.add_TLV(2, matter.TLV.B1, self.cB)
return s.encode()
end
end
matter.Pake2 = Matter_Pake2
# class Pake3
class Matter_Pake3
var cA
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)
self.cA = val.getsubval(1)
return self
end
end
matter.Pake3 = Matter_Pake3
#################################################################################
# class Sigma1, p.160
#################################################################################
class Matter_Sigma1
var initiatorRandom # bytes(32)
var initiator_session_id # U16
var destinationId # bytes(32)
var initiatorEphPubKey # bytes(65)
# var initiatorSEDParams # (opt) sed-parameter-struct
var SLEEPY_IDLE_INTERVAL
var SLEEPY_ACTIVE_INTERVAL
var resumptionID # (opt) bytes(16)
var initiatorResumeMIC # (opt) bytes(16)
var Msg1
def parse(b, idx)
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)
self.initiatorRandom = val.getsubval(1)
self.initiator_session_id = val.getsubval(2)
self.destinationId = val.getsubval(3)
self.initiatorEphPubKey = val.getsubval(4)
var initiatorSEDParams = val.findsub(5)
if initiatorSEDParams != nil
self.SLEEPY_IDLE_INTERVAL = initiatorSEDParams.findsubval(1)
self.SLEEPY_ACTIVE_INTERVAL = initiatorSEDParams.findsubval(2)
end
var resumptionID = val.findsub(6)
var initiatorResumeMIC = val.findsub(7)
return self
end
end
matter.Sigma1 = Matter_Sigma1
#################################################################################
# class Sigma2
#################################################################################
class Matter_Sigma2
var responderRandom # bytes(32)
var responderSessionId # U16
var responderEphPubKey # bytes(65)
var encrypted2 # bytes()
var SLEEPY_IDLE_INTERVAL
var SLEEPY_ACTIVE_INTERVAL
def encode(b)
var s = matter.TLV.Matter_TLV_struct()
# initiatorRandom
s.add_TLV(1, matter.TLV.B1, self.responderRandom)
s.add_TLV(2, matter.TLV.U2, self.responderSessionId)
s.add_TLV(3, matter.TLV.B1, self.responderEphPubKey)
s.add_TLV(4, matter.TLV.B1, self.encrypted2)
if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil
var s2 = s.add_struct(5)
s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL)
s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL)
end
return s.encode()
end
end
matter.Sigma2 = Matter_Sigma2
#################################################################################
# class Sigma2Resume, p.170
#################################################################################
class Matter_Sigma2Resume
var resumptionID # bytes(16)
var sigma2ResumeMIC # bytes(16)
var responderSessionID # u16
var SLEEPY_IDLE_INTERVAL
var SLEEPY_ACTIVE_INTERVAL
def encode(b)
var s = matter.TLV.Matter_TLV_struct()
# initiatorRandom
s.add_TLV(1, matter.TLV.B1, self.resumptionID)
s.add_TLV(2, matter.TLV.B1, self.sigma2ResumeMIC)
s.add_TLV(3, matter.TLV.B1, self.responderSessionID)
if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil
var s2 = s.add_struct(4)
s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL)
s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL)
end
return s.encode()
end
end
matter.Sigma2Resume = Matter_Sigma2Resume
#################################################################################
# class Sigma3, p.160
#################################################################################
class Matter_Sigma3
var TBEData3Encrypted # bytes()
var Msg3
def parse(b, idx)
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)
self.TBEData3Encrypted = val.getsubval(1)
return self
end
end
matter.Sigma3 = Matter_Sigma3
#-
# STEP 1
PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'),
'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461}
# ##########################################################################################
PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
print(matter.inspect(PBKDF_PR))
{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), 'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461}
var r = matter.PBKDFParamResponse()
r.initiatorRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00")
r.responderRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00")
r.responderSessionId = 1234
r.pbkdf_parameters_iterations = 1000
r.pbkdf_parameters_salt = bytes("deadbeef11223344deadbeef11223344")
r.SLEEPY_IDLE_INTERVAL = 100
r.SLEEPY_ACTIVE_INTERVAL = 200
bytes('15300120112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00300220112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF002503D20418')
# ##########################################################################################
var m = matter.Frame()
m.decode(bytes("0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"))
# 'opcode': 32
# 'local_session_id': 0
# 'protocol_id': 0
#{'dest_node_id_8': nil, 'flag_dsiz': 0, 'x_flag_r': 1, 'sec_c': 0, 'app_payload_idx': 22, 'sec_flags': 0,
#'dest_node_id_2': nil, 'x_flag_sx': 0, 'sec_p': 0, 'message_counter': 159020038, 'x_flag_v': 0, 'flags': 4,
#'vendor_id': nil, 'x_flag_i': 1, 'source_node_id': bytes('347BFD880AC81280'),
#'ack_message_counter': nil, 'raw': bytes('0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9...'),
#'exchange_id': 50015, 'opcode': 32, 'local_session_id': 0, 'x_flag_a': 0, 'flag_s': 1, 'x_flags': 5, 'sec_sesstype': 0,
#'sec_extensions': nil, 'sec_mx': 0, 'protocol_id': 0}
0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818
12:09:05.561 MTR: sending packet to '192.168.2.109:5540' 050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018
050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018
12:10:29.174 MTR: received message {
'flag_s': 1, 'flag_dsiz': 1, 'x_flag_r': 1, 'x_flag_sx': 1, 'sec_mx': 0, 'sec_flags': 0,
'dest_node_id_2': nil, 'sec_sesstype': 0, 'local_session_id': 0, 'ack_message_counter': -2014389550,
'x_flag_v': 1, 'flags': 5, 'vendor_id': 8193, 'x_flag_i': 1, 'source_node_id': bytes('96B90B530000347B'),
'app_payload_idx': 51590,
'raw': bytes('050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120...'),
'exchange_id': 0, 'opcode': 195, 'message_counter': 734557190, 'sec_p': 0, 'sec_c': 0,
'protocol_id': 12309, 'dest_node_id_8': bytes('FD880AC812800021'),
'sec_extensions': nil, 'x_flag_a': 1, 'x_flags': 95}
347BFD880AC81280
fe80::1bf1:bd1a:c5ff:818a
b8:27:eb:8b:d2:59
{'mac': 'C8:2B:96:B9:0B:53', 'ip6local': 'fe80::ca2b:96ff:feb9:b53', 'ip': '192.168.1.116'}
-#

View File

@ -0,0 +1,508 @@
#
# Matter_Device.be - implements a generic Matter device (commissionee)
#
# 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/>.
#
#@ solidify:Matter_Device,weak
class Matter_Device
static var UDP_PORT = 5540 # this is the default port for group multicast, we also use it for unicast
static var PASSCODE_DEFAULT = 20202021
static var PBKDF_ITERATIONS = 1000 # I don't see any reason to choose a different number
static var VENDOR_ID = 0xFFF1
static var PRODUCT_ID = 0x8000
static var FILENAME = "_matter_device.json"
var plugins # list of plugins
var udp_server # `matter.UDPServer()` object
var msg_handler # `matter.MessageHandler()` object
var sessions # `matter.Session_Store()` objet
var ui
# information about the device
var commissioning_instance_wifi # random instance name for commissioning
var commissioning_instance_eth # random instance name for commissioning
var hostname_wifi # MAC-derived hostname for commissioning
var hostname_eth # MAC-derived hostname for commissioning
var vendorid
var productid
var discriminator
# context for PBKDF
var passcode
var iterations
# PBKDF information used only during PASE (freed afterwards)
var salt
var w0, w1, L
#############################################################
def init()
import crypto
import string
if !tasmota.get_option(matter.MATTER_OPTION)
matter.UI(self) # minimal UI
return
end # abort if SetOption 151 is not set
self.plugins = []
self.vendorid = self.VENDOR_ID
self.productid = self.PRODUCT_ID
self.iterations = self.PBKDF_ITERATIONS
self.load_param()
self.commissioning_instance_wifi = crypto.random(8).tohex() # 16 characters random hostname
self.commissioning_instance_eth = crypto.random(8).tohex() # 16 characters random hostname
self.sessions = matter.Session_Store()
self.sessions.load()
self.msg_handler = matter.MessageHandler(self)
self.ui = matter.UI(self)
# add the default plugin
self.plugins.push(matter.Plugin_core(self))
self.start_mdns_announce_hostnames()
if tasmota.wifi()['up']
self.start_udp(self.UDP_PORT)
else
tasmota.add_rule("Wifi#Connected", def ()
self.start_udp(self.UDP_PORT)
tasmota.remove_rule("Wifi#Connected", "matter_device_udp")
end, self)
end
if tasmota.eth()['up']
self.start_udp(self.UDP_PORT)
else
tasmota.add_rule("Eth#Connected", def ()
self.start_udp(self.UDP_PORT)
tasmota.remove_rule("Eth#Connected", "matter_device_udp")
end, self)
end
self.start_basic_commissioning()
tasmota.add_driver(self)
end
#############################################################
# Start Basic Commissioning Window
def start_basic_commissioning()
# compute PBKDF
self.compute_pbkdf(self.passcode)
end
def finish_commissioning()
end
#############################################################
# Compute the PBKDF parameters for SPAKE2+
#
# iterations is set to 1000 which is large enough
def compute_pbkdf(passcode_int)
import crypto
self.salt = crypto.random(16) # bytes("5350414B453250204B65792053616C74")
var passcode = bytes().add(passcode_int, 4)
var tv = crypto.PBKDF2_HMAC_SHA256().derive(passcode, self.salt, self.iterations, 80)
var w0s = tv[0..39]
var w1s = tv[40..79]
self.w0 = crypto.EC_P256().mod(w0s)
self.w1 = crypto.EC_P256().mod(w1s)
self.L = crypto.EC_P256().public_key(self.w1)
tasmota.log("MTR: ******************************", 3)
tasmota.log("MTR: salt = " + self.salt.tohex(), 3)
tasmota.log("MTR: passcode = " + passcode.tohex(), 3)
tasmota.log("MTR: w0 = " + self.w0.tohex(), 3)
tasmota.log("MTR: w1 = " + self.w1.tohex(), 3)
tasmota.log("MTR: L = " + self.L.tohex(), 3)
tasmota.log("MTR: ******************************", 3)
end
#############################################################
# compute QR Code content
def compute_qrcode_content()
var raw = bytes().resize(11) # we don't use TLV Data so it's only 88 bits or 11 bytes
# version is `000` dont touch
raw.setbits(3, 16, self.vendorid)
raw.setbits(19, 16, self.productid)
# custom flow = 0 (offset=35, len=2)
raw.setbits(37, 8, 0x04) # already on IP network
raw.setbits(45, 12, self.discriminator & 0xFFF)
raw.setbits(57, 27, self.passcode & 0x7FFFFFF)
# padding (offset=84 len=4)
return "MT:" + matter.Base38.encode(raw)
end
#############################################################
# compute the 11 digits manual pairing code (wihout vendorid nor productid) p.223
def compute_manual_pairing_code()
import string
var digit_1 = (self.discriminator & 0x0FFF) >> 10
var digit_2_6 = ((self.discriminator & 0x0300) << 6) | (self.passcode & 0x3FFF)
var digit_7_10 = (self.passcode >> 14)
var ret = string.format("%1i%05i%04i", digit_1, digit_2_6, digit_7_10)
ret += matter.Verhoeff.checksum(ret)
return ret
end
#############################################################
# dispatch every second click to sub-objects that need it
def every_second()
self.sessions.every_second()
self.msg_handler.every_second()
end
#############################################################
def stop()
if self.udp_server self.udp_server.stop() end
end
#############################################################
# callback when message is received
def msg_received(raw, addr, port)
return self.msg_handler.msg_received(raw, addr, port)
end
def msg_send(raw, addr, port, id)
return self.udp_server.send_response(raw, addr, port, id)
end
def packet_ack(id)
return self.udp_server.packet_ack(id)
end
#############################################################
# Start UDP Server
def start_udp(port)
if self.udp_server return end # already started
if port == nil port = 5540 end
tasmota.log("MTR: starting UDP server on port: " + str(port), 2)
self.udp_server = matter.UDPServer("", port)
self.udp_server.start(/ raw, addr, port -> self.msg_received(raw, addr, port))
end
#############################################################
# start_operational_dicovery
#
# Pass control to `device`
def start_operational_dicovery_deferred(session)
# defer to next click
tasmota.set_timer(0, /-> self.start_operational_dicovery(session))
end
#############################################################
def start_commissioning_complete_deferred(session)
# defer to next click
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)
import crypto
import mdns
import string
# clear any PBKDF information to free memory
self.salt = nil
self.w0 = nil
self.w1 = nil
self.L = nil
# save session as persistant
session.set_no_expiration()
session.set_persist(true)
# close the PASE session, it will be re-opened with a CASE session
session.close()
self.sessions.save()
self.mdns_announce_op_discovery(session)
end
#############################################################
# Commissioning Complete
#
def start_commissioning_complete(session)
tasmota.log("MTR: *** Commissioning complete ***", 2)
end
#############################################################
# read an attribute
#
def read_attribute(msg, endpoint, cluster, attribute)
var idx = 0
while idx < size(self.plugins)
var plugin = self.plugins[idx]
var ret = plugin.read_attribute(msg, endpoint, cluster, attribute)
if ret != nil
return ret
end
idx += 1
end
end
#############################################################
# Persistance of Matter Device parameters
#
#############################################################
#
def save_param()
import json
var j = json.dump({'distinguish':self.discriminator, 'passcode':self.passcode})
try
import string
var f = open(self.FILENAME, "w")
f.write(j)
f.close()
return j
except .. as e, m
tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2)
return j
end
end
#############################################################
def load_param()
import string
import crypto
try
var f = open(self.FILENAME)
var s = f.read()
f.close()
import json
var j = json.load(s)
self.discriminator = j.find("distinguish")
self.passcode = j.find("passcode")
except .. as e, m
if e != "io_error"
tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2)
end
end
var dirty = false
if self.discriminator == nil
self.discriminator = crypto.random(2).get(0,2) & 0xFFF
dirty = true
end
if self.passcode == nil
self.passcode = self.PASSCODE_DEFAULT
dirty = true
end
if dirty self.save_param() end
end
#############################################################
# Matter plugin management
#
# Plugins allow to specify response to read/write attributes
# and command invokes
#############################################################
def invoke_request(msg, val, ctx)
var idx = 0
while idx < size(self.plugins)
var plugin = self.plugins[idx]
var ret = plugin.invoke_request(msg, val, ctx)
if ret != nil || ctx.status != matter.UNSUPPORTED_COMMAND # default value
return ret
end
idx += 1
end
end
#############################################################
# MDNS Configuration
#############################################################
# Start MDNS and announce hostnames for Wifi and ETH from MAC
#
# When the announce is active, `hostname_wifi` and `hostname_eth`
# are defined
def start_mdns_announce_hostnames()
if tasmota.wifi()['up']
self._start_mdns_announce(false)
else
tasmota.add_rule("Wifi#Connected", def ()
self._start_mdns_announce(false)
tasmota.remove_rule("Wifi#Connected", "matter_device_mdns")
end, self)
end
if tasmota.eth()['up']
self._start_mdns_announce(true)
else
tasmota.add_rule("Eth#Connected", def ()
self._start_mdns_announce(true)
tasmota.remove_rule("Eth#Connected", "matter_device_mdns")
end, self)
end
end
#############################################################
# Start UDP mDNS announcements for commissioning
#
# eth is `true` if ethernet turned up, `false` is wifi turned up
def _start_mdns_announce(is_eth)
import mdns
import string
mdns.start()
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
}
# mdns
try
if is_eth
var eth = tasmota.eth()
self.hostname_eth = string.replace(eth.find("mac"), ':', '')
mdns.add_hostname(self.hostname_eth, eth.find('ip6local',''), eth.find('ip',''), eth.find('ip6',''))
mdns.add_service("_matterc", "_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth)
tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi",
is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi,
is_eth ? self.hostname_eth : self.hostname_wifi), 2)
# `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil`
var subtype = "_L" + str(self.discriminator & 0xFFF)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype)
subtype = "_S" + str((self.discriminator & 0xF00) >> 8)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype)
subtype = "_V" + str(self.vendorid)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype)
subtype = "_CM1"
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype)
else
var wifi = tasmota.wifi()
self.hostname_wifi = string.replace(wifi.find("mac"), ':', '')
mdns.add_hostname(self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip',''), wifi.find('ip6',''))
mdns.add_service("_matter", "_tcp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi)
tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi",
is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi,
is_eth ? self.hostname_eth : self.hostname_wifi), 2)
# `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil`
var subtype = "_L" + str(self.discriminator & 0xFFF)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype)
subtype = "_S" + str((self.discriminator & 0xF00) >> 8)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype)
subtype = "_V" + str(self.vendorid)
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype)
subtype = "_CM1"
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype)
end
except .. as e, m
tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2)
end
self.mdns_announce_op_discovery_all_sessions()
end
#############################################################
# Start UDP mDNS announcements for commissioning for all persisted sessions
def mdns_announce_op_discovery_all_sessions()
for session: self.sessions.sessions
if session.get_deviceid() && session.get_fabric()
self.mdns_announce_op_discovery(session)
end
end
end
#############################################################
# Start UDP mDNS announcements for commissioning
def mdns_announce_op_discovery(session)
import mdns
import string
try
var device_id = session.get_deviceid().copy().reverse()
var k_fabric = session.get_fabric_compressed()
var op_node = k_fabric.tohex() + "-" + device_id.tohex()
tasmota.log("MTR: Operational Discovery node = " + op_node, 2)
# mdns
if (tasmota.eth().find("up"))
tasmota.log(string.format("MTR: adding mDNS on %s '%s' ptr to `%s.local`", "eth", op_node, self.hostname_eth), 3)
mdns.add_service("_matter","_tcp", 5540, nil, op_node, self.hostname_eth)
var subtype = "_I" + k_fabric.tohex()
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matter", "_tcp", op_node, self.hostname_eth, subtype)
end
if (tasmota.wifi().find("up"))
tasmota.log(string.format("MTR: adding mDNS on %s '%s' ptr to `%s.local`", "wifi", op_node, self.hostname_wifi), 3)
mdns.add_service("_matter","_tcp", 5540, nil, op_node, self.hostname_wifi)
var subtype = "_I" + k_fabric.tohex()
tasmota.log("MTR: adding subtype: "+subtype, 3)
mdns.add_subtype("_matter", "_tcp", op_node, self.hostname_wifi, subtype)
end
except .. as e, m
tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2)
end
end
end
matter.Device = Matter_Device
#-
import global
global.matter_device = matter_device()
return matter_device
-#

View File

@ -0,0 +1,326 @@
#
# Matter_IM.be - suppport for Matter Interaction Model
#
# 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_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
end
matter.Response_container = Matter_Response_container
#################################################################################
# Matter_IM class
#################################################################################
class Matter_IM
var responder
def init(responder)
self.responder = responder
end
def process_incoming(msg, remote_ip, remote_port)
# messages are always TLV, decode payload
tasmota.log("MTR: received IM message " + matter.inspect(msg), 3)
var val = matter.TLV.parse(msg.raw, msg.app_payload_idx)
tasmota.log("MTR: IM TLV: " + str(val), 3)
var InteractionModelRevision = val.findsubval(0xFF)
tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 3)
var opcode = msg.opcode
if opcode == 0x01 # Status Response
return self.process_status_response(msg, val, remote_ip, remote_port)
elif opcode == 0x02 # Read Request
return self.process_read_request(msg, val, remote_ip, remote_port)
elif opcode == 0x03 # Subscribe Request
return self.subscribe_request(msg, val, remote_ip, remote_port)
elif opcode == 0x04 # Subscribe Response
return self.subscribe_response(msg, val, remote_ip, remote_port)
elif opcode == 0x05 # Report Data
return self.report_data(msg, val, remote_ip, remote_port)
elif opcode == 0x06 # Write Request
return self.process_write_request(msg, val, remote_ip, remote_port)
elif opcode == 0x07 # Write Response
return self.process_write_response(msg, val, remote_ip, remote_port)
elif opcode == 0x08 # Invoke Request
return self.process_invoke_request(msg, val, remote_ip, remote_port)
elif opcode == 0x09 # Invoke Response
return self.process_invoke_response(msg, val, remote_ip, remote_port)
elif opcode == 0x0A # Timed Request
return self.process_timed_request(msg, val, remote_ip, remote_port)
end
return false
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, remote_ip, remote_port)
import string
var status = val.findsubval(0, 0xFF)
tasmota.log(string.format("MTR: Status Response = 0x%02X", status), 3)
return true
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, remote_ip, remote_port)
# structure is `ReadRequestMessage` 10.6.2 p.558
tasmota.log("MTR: IM:read_request processing start", 3)
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 = []
# TODO - we need to implement Concrete path expansion here
for q:query.attributes_requests
var attr_name = matter.get_attribute_name(q.cluster, q.attribute)
tasmota.log("MTR: Read Attribute " + str(q) + (attr_name ? " (" + attr_name + ")" : ""), 2)
var res = self.responder.device.read_attribute(msg, q.endpoint, q.cluster, q.attribute)
if res != nil
var a1 = matter.AttributeReportIB()
# a1.attribute_status = matter.AttributeStatusIB()
# a1.attribute_status.path = matter.AttributePathIB()
# a1.attribute_status.status = matter.StatusIB()
# a1.attribute_status.path.endpoint = 0
# a1.attribute_status.path.cluster = q.cluster
# a1.attribute_status.path.attribute = q.attribute
# a1.attribute_status.status.status = matter.SUCCESS
a1.attribute_data = matter.AttributeDataIB()
a1.attribute_data.data_version = 1
a1.attribute_data.path = matter.AttributePathIB()
a1.attribute_data.path.endpoint = 0
a1.attribute_data.path.cluster = q.cluster
a1.attribute_data.path.attribute = q.attribute
a1.attribute_data.data = res
ret.attribute_reports.push(a1)
end
end
tasmota.log("MTR: ReportDataMessage=" + str(ret), 3)
tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3)
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, remote_ip, remote_port, resp.message_counter)
end
return true
end
#############################################################
# process IM 0x08 Invoke Request
#
# val is the TLV structure
# returns `true` if processed, `false` if silently ignored,
# or raises an exception
def process_invoke_request(msg, val, remote_ip, remote_port)
import string
# structure is `ReadRequestMessage` 10.6.2 p.558
tasmota.log("MTR: IM:invoke_request processing start", 3)
var ctx = matter.Response_container()
var query = matter.InvokeRequestMessage().from_TLV(val)
if query.invoke_requests != nil
# prepare the response
var ret = matter.InvokeResponseMessage()
ret.suppress_response = false
ret.invoke_responses = []
for q:query.invoke_requests
ctx.endpoint = q.command_path.endpoint
ctx.cluster = q.command_path.cluster
ctx.command = q.command_path.command
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, remote_ip, remote_port), 2)
var res = self.responder.device.invoke_request(msg, q.command_fields, ctx)
var a1 = matter.InvokeResponseIB()
if res != nil
a1.command = matter.CommandDataIB()
a1.command.command_path = matter.CommandPathIB()
a1.command.command_path.endpoint = ctx.endpoint
a1.command.command_path.cluster = ctx.cluster
a1.command.command_path.command = ctx.command
a1.command.command_fields = res
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)
elif ctx.status != nil
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 = ctx.status
ret.invoke_responses.push(a1)
else
# ignore if content is nil and status is undefined
end
end
tasmota.log("MTR: invoke_responses="+str(ret.invoke_responses), 3)
if size(ret.invoke_responses) > 0
tasmota.log("MTR: InvokeResponse=" + str(ret), 3)
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, remote_ip, 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, remote_ip, remote_port, resp.message_counter)
end
end
end
#############################################################
# process IM 0x03 Subscribe Request
#
def subscribe_request(msg, val, remote_ip, remote_port)
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, remote_ip, remote_port)
import string
var query = matter.SubscribeResponseMessage().from_TLV(val)
tasmota.log("MTR: received SubscribeResponsetMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x05 ReportData
#
def report_data(msg, val, remote_ip, remote_port)
import string
var query = matter.ReportDataMessage().from_TLV(val)
tasmota.log("MTR: received ReportDataMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x06 Write Request
#
def process_write_request(msg, val, remote_ip, remote_port)
import string
var query = matter.WriteRequestMessage().from_TLV(val)
tasmota.log("MTR: received WriteRequestMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x07 Write Response
#
def process_write_response(msg, val, remote_ip, remote_port)
import string
var query = matter.WriteResponseMessage().from_TLV(val)
tasmota.log("MTR: received WriteResponseMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x09 Invoke Response
#
def process_invoke_response(msg, val, remote_ip, remote_port)
import string
var query = matter.InvokeResponseMessage().from_TLV(val)
tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 3)
return false
end
#############################################################
# process IM 0x0A Timed Request
#
def process_timed_request(msg, val, remote_ip, remote_port)
import string
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, remote_ip, 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, remote_ip, remote_port, resp.message_counter)
return true
end
#############################################################
# placeholder, nothing to run for now
def every_second()
end
end
matter.IM = Matter_IM
#-
# Unit tests
-#

View File

@ -0,0 +1,946 @@
#
# Matter_IM_Data.be - suppport for Matter Interation Model messages structure
#
# 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_base,weak
#@ solidify:Matter_IM_Message_base,weak
#@ solidify:matter.AttributePathIB,weak
#@ solidify:matter.ClusterPathIB,weak
#@ solidify:matter.DataVersionFilterIB,weak
#@ solidify:matter.AttributeDataIB,weak
#@ solidify:matter.AttributeReportIB,weak
#@ solidify:matter.EventFilterIB,weak
#@ solidify:matter.EventPathIB,weak
#@ solidify:matter.EventDataIB,weak
#@ solidify:matter.EventReportIB,weak
#@ solidify:matter.CommandPathIB,weak
#@ solidify:matter.CommandDataIB,weak
#@ solidify:matter.InvokeResponseIB,weak
#@ solidify:matter.CommandStatusIB,weak
#@ solidify:matter.EventStatusIB,weak
#@ solidify:matter.AttributeStatusIB,weak
#@ solidify:matter.StatusIB,weak
#@ solidify:matter.StatusResponseMessage,weak
#@ solidify:matter.ReadRequestMessage,weak
#@ solidify:matter.ReportDataMessage,weak
#@ solidify:matter.SubscribeRequestMessage,weak
#@ solidify:matter.SubscribeResponseMessage,weak
#@ solidify:matter.WriteRequestMessage,weak
#@ solidify:matter.WriteResponseMessage,weak
#@ solidify:matter.TimedRequestMessage,weak
#@ solidify:matter.InvokeRequestMessage,weak
#@ solidify:matter.InvokeResponseMessage,weak
#################################################################################
# Base class for all IM containers
#################################################################################
class Matter_IM_base
def tostring()
return "<" + classname(self) + ":" + matter.inspect(self) + ">"
end
# arr: array (list) of TLV values
# cl: class for the TLV decoder
def from_TLV_array(arr, cl)
if arr == nil return nil end
var r = []
for v:arr
r.push(cl().from_TLV(v))
end
return r
end
# add an array of objects to TLV
# s: current container to add to
# tag: tag for the array (inner items don't have tags)
# arr: the array of objects supporting `to_TLV()`
#
# if arr is `nil`, nothing happens
def to_TLV_array(s, tag, arr)
if arr == nil return nil end
var l = s.add_array(tag) # create the list container and add to the current container
for v:arr
l.add_obj(nil, v)
end
end
end
#################################################################################
# Matter_AttributePathIB class
#################################################################################
class Matter_AttributePathIB : Matter_IM_base
var tag_compression # false if none
var node # u64 as bytes
var endpoint # u16
var cluster # u32
var attribute # u32
var list_index # ?
def tostring()
try
import string
var s = ""
if self.node s += string.format("node=%s ", self.node) end
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) : "****")
return s
except .. as e, m
return "Exception> " + str(e) + ", " + str(m)
end
end
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.tag_compression = val.findsubval(0)
self.node = val.findsubval(1)
self.endpoint = val.findsubval(2)
self.cluster = val.findsubval(3)
self.attribute = val.findsubval(4)
self.list_index = val.findsubval(5)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, TLV.BOOL, self.tag_compression)
s.add_TLV(1, TLV.U8, self.node)
s.add_TLV(2, TLV.U2, self.endpoint)
s.add_TLV(3, TLV.U4, self.cluster)
s.add_TLV(4, TLV.U4, self.attribute)
s.add_TLV(5, TLV.U2, self.list_index)
return s
end
end
matter.AttributePathIB = Matter_AttributePathIB
#################################################################################
# ClusterPathIB class
#################################################################################
class Matter_ClusterPathIB : Matter_IM_base
var node # u64 as bytes
var endpoint # u16
var cluster # u32
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.node = val.findsubval(0)
self.endpoint = val.findsubval(1)
self.cluster = val.findsubval(2)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, TLV.U8, self.node)
s.add_TLV(1, TLV.U2, self.endpoint)
s.add_TLV(2, TLV.U4, self.cluster)
return s
end
end
matter.ClusterPathIB = Matter_ClusterPathIB
#################################################################################
# DataVersionFilterIB class
#################################################################################
class Matter_DataVersionFilterIB : Matter_IM_base
var path # false if none
var data_version # u64 as bytes
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.path = matter.ClusterPathIB().from_TLV(val.findsub(0))
self.data_version = val.findsubval(1) # u32
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.path)
s.add_TLV(1, TLV.U4, self.data_version)
return s
end
end
matter.DataVersionFilterIB = Matter_DataVersionFilterIB
#################################################################################
# AttributeDataIB class
#################################################################################
class Matter_AttributeDataIB : Matter_IM_base
var data_version # u32
var path # AttributePathIB
var data # any TLV
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.data_version = val.findsubval(0) # u32
self.path = matter.AttributePathIB().from_TLV(val.findsub(1))
self.data = val.findsubval(2) # any
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U4, self.data_version)
s.add_obj(1, self.path)
s.add_obj(2, self.data)
return s
end
end
matter.AttributeDataIB = Matter_AttributeDataIB
#################################################################################
# AttributeReportIB class
#################################################################################
class Matter_AttributeReportIB : Matter_IM_base
var attribute_status # AttributeStatusIB
var attribute_data # AttributeDataIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.attribute_status = matter.AttributeStatusIB().from_TLV(val.findsub(0))
self.attribute_data = matter.AttributeDataIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.attribute_status)
s.add_obj(1, self.attribute_data)
return s
end
end
matter.AttributeReportIB = Matter_AttributeReportIB
#################################################################################
# EventFilterIB class
#################################################################################
class Matter_EventFilterIB : Matter_IM_base
var node # u64
var event_min # u64
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.node = val.findsubval(0)
self.event_min = val.findsubval(1)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U8, self.node)
s.add_TLV(1, TLV.U8, self.event_min)
return s
end
end
matter.EventFilterIB = Matter_EventFilterIB
#################################################################################
# EventPathIB class
#################################################################################
class Matter_EventPathIB : Matter_IM_base
var node # u64 as bytes
var endpoint # u16
var cluster # u32
var event # u32
var is_urgent # bool
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.node = val.findsubval(0)
self.endpoint = val.findsubval(1)
self.cluster = val.findsubval(2)
self.event = val.findsubval(3)
self.is_urgent = val.findsubval(4)
return self
end
def to_TLV(s)
var TLV = matter.TLV
if s == nil s = TLV.Matter_TLV_list() end
s.add_TLV(0, TLV.U8, self.node)
s.add_TLV(1, TLV.U2, self.endpoint)
s.add_TLV(2, TLV.U4, self.cluster)
s.add_TLV(3, TLV.U4, self.event)
s.add_TLV(4, TLV.BOOL, self.is_urgent)
return s
end
end
matter.EventPathIB = Matter_EventPathIB
#################################################################################
# EventDataIB class
#################################################################################
class Matter_EventDataIB : Matter_IM_base
var path #
var event_number # u64 as bytes
var priority # u8
# one of
var epoch_timestamp # u64
var system_timestamp # u64
var delta_epoch_timestamp # u64
var delta_system_timestamp # u64
# data
var data # any TLV
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.path = matter.EventPathIB().from_TLV(val.findsub(0))
self.event_number = val.findsubval(1) # u64
self.priority = val.findsubval(2) # u64
self.epoch_timestamp = val.findsubval(3) # u64
self.system_timestamp = val.findsubval(4) # u64
self.delta_epoch_timestamp = val.findsubval(5) # u64
self.delta_system_timestamp = val.findsubval(6) # u64
self.data = val.findsubval(7) # any
return self
end
def to_TLV(s)
var TLV = matter.TLV
if s == nil s = TLV.Matter_TLV_struct() end
if self.path
self.path.to_TLV(s.add_list(0))
end
s.add_TLV(1, TLV.U8, self.event_number)
s.add_TLV(2, TLV.U1, self.priority)
s.add_TLV(3, TLV.U8, self.epoch_timestamp)
s.add_TLV(4, TLV.U8, self.system_timestamp)
s.add_TLV(5, TLV.U8, self.delta_epoch_timestamp)
s.add_TLV(6, TLV.U8, self.delta_system_timestamp)
s.add_obj(7, self.data)
return s
end
end
matter.EventDataIB = Matter_EventDataIB
#################################################################################
# EventReportIB class
#################################################################################
class Matter_EventReportIB : Matter_IM_base
var event_status # EventStatusIB
var event_data # EventDataIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.event_status = matter.EventStatusIB().from_TLV(val.findsub(0))
self.event_data = matter.EventDataIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.event_status)
s.add_obj(1, self.event_data)
return s
end
end
matter.EventReportIB = Matter_EventReportIB
#################################################################################
# CommandPathIB class
#################################################################################
class Matter_CommandPathIB : Matter_IM_base
var endpoint # u16
var cluster # u32
var command # u32
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.endpoint = val.findsubval(0)
self.cluster = val.findsubval(1)
self.command = val.findsubval(2)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, TLV.U2, self.endpoint)
s.add_TLV(1, TLV.U4, self.cluster)
s.add_TLV(2, TLV.U4, self.command)
return s
end
end
matter.CommandPathIB = Matter_CommandPathIB
#################################################################################
# CommandDataIB class
#################################################################################
class Matter_CommandDataIB : Matter_IM_base
var command_path # CommandPathIB
var command_fields # any
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.command_path = matter.CommandPathIB().from_TLV(val.findsub(0))
self.command_fields = val.findsub(1)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.command_path)
s.add_obj(1, self.command_fields)
return s
end
end
matter.CommandDataIB = Matter_CommandDataIB
#################################################################################
# InvokeResponseIB class
#################################################################################
class Matter_InvokeResponseIB : Matter_IM_base
var command # CommandDataIB
var status # CommandStatusIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.command = matter.CommandDataIB().from_TLV(val.findsub(0))
self.status = matter.CommandStatusIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.command)
s.add_obj(1, self.status)
return s
end
end
matter.InvokeResponseIB = Matter_InvokeResponseIB
#################################################################################
# CommandStatusIB class
#################################################################################
class Matter_CommandStatusIB : Matter_IM_base
var command_path # CommandPathIB
var status # StatusIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.command_path = matter.CommandPathIB().from_TLV(val.findsub(0))
self.status = matter.StatusIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.command_path)
s.add_obj(1, self.status)
return s
end
end
matter.CommandStatusIB = Matter_CommandStatusIB
#################################################################################
# EventStatusIB class
#################################################################################
class Matter_EventStatusIB : Matter_IM_base
var path # EventPathIB
var status # StatusIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.path = matter.EventPathIB().from_TLV(val.findsub(0))
self.status = matter.StatusIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.path)
s.add_obj(1, self.status)
return s
end
end
matter.EventStatusIB = Matter_EventStatusIB
#################################################################################
# AttributeStatusIB class
#################################################################################
class Matter_AttributeStatusIB : Matter_IM_base
var path # AttributePathIB
var status # StatusIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.path = matter.AttributePathIB().from_TLV(val.findsub(0))
self.status = matter.StatusIB().from_TLV(val.findsub(1))
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_obj(0, self.path)
s.add_obj(1, self.status)
return s
end
end
matter.AttributeStatusIB = Matter_AttributeStatusIB
#################################################################################
# StatusIB class
#################################################################################
class Matter_StatusIB : Matter_IM_base
var status # u16
var cluster_status # u16
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.status = val.findsubval(0)
self.cluster_status = val.findsubval(1)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_list()
s.add_TLV(0, TLV.U2, self.status)
s.add_TLV(1, TLV.U2, self.cluster_status)
return s
end
end
matter.StatusIB = Matter_StatusIB
#################################################################################
#################################################################################
# Matter_IM_Message_base class
#
# This is the superclass for all high-level messages
#################################################################################
#################################################################################
class Matter_IM_Message_base : Matter_IM_base
var InteractionModelRevision # 0xFF
def init()
self.InteractionModelRevision = 1
end
end
#################################################################################
# StatusResponseMessage class
#################################################################################
class Matter_StatusResponseMessage : Matter_IM_Message_base
var status # u32
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.status = val.findsubval(0)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U4, self.status)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.StatusResponseMessage = Matter_StatusResponseMessage
#################################################################################
# ReadRequestMessage class
#################################################################################
class Matter_ReadRequestMessage : Matter_IM_Message_base
var attributes_requests # array of AttributePathIB
var event_requests # array of EventPathIB
var event_filters # array of EventFilterIB
var fabric_filtered # bool
var data_version_filters # array of DataVersionFilterIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.attributes_requests = self.from_TLV_array(val.findsubval(0), matter.AttributePathIB)
self.event_requests = self.from_TLV_array(val.findsubval(1), matter.EventPathIB)
self.event_filters = self.from_TLV_array(val.findsubval(2), matter.EventFilterIB)
self.fabric_filtered = val.findsubval(3)
self.data_version_filters = self.from_TLV_array(val.findsubval(4), matter.DataVersionFilterIB)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
self.to_TLV_array(s, 0, self.attributes_requests)
self.to_TLV_array(s, 1, self.event_requests)
self.to_TLV_array(s, 2, self.event_filters)
s.add_TLV(3, TLV.BOOL, self.fabric_filtered)
self.to_TLV_array(s, 4, self.data_version_filters)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.ReadRequestMessage = Matter_ReadRequestMessage
#################################################################################
# ReportDataMessage class
#################################################################################
class Matter_ReportDataMessage : Matter_IM_Message_base
var subscription_id # u32
var attribute_reports # array of AttributeReportIB
var event_reports # array of EventReportIB
var more_chunked_messages # bool
var suppress_response # bool
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.subscription_id = val.findsubval(0)
self.attribute_reports = self.from_TLV_array(val.findsubval(1), matter.AttributeReportIB)
self.event_reports = self.from_TLV_array(val.findsubval(2), matter.EventReportIB)
self.more_chunked_messages = val.findsubval(3)
self.suppress_response = val.findsubval(4)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U4, self.subscription_id)
self.to_TLV_array(s, 1, self.attribute_reports)
self.to_TLV_array(s, 2, self.event_reports)
s.add_TLV(3, TLV.BOOL, self.more_chunked_messages)
s.add_TLV(4, TLV.BOOL, self.suppress_response)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.ReportDataMessage = Matter_ReportDataMessage
#################################################################################
# SubscribeRequestMessage class
#################################################################################
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 event_requests # array of EventPathIB
var event_filters # array of EventFilterIB
var fabric_filtered # bool
var data_version_filters # array of DataVersionFilterIB
# 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.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.data_version_filters = self.from_TLV_array(val.findsubval(8), matter.DataVersionFilterIB)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
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, 4, self.event_requests)
self.to_TLV_array(s, 5, self.event_filters)
s.add_TLV(7, TLV.BOOL, self.fabric_filtered)
self.to_TLV_array(s, 8, self.data_version_filters)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.SubscribeRequestMessage = Matter_SubscribeRequestMessage
#################################################################################
# SubscribeResponseMessage class
#################################################################################
class Matter_SubscribeResponseMessage : Matter_IM_Message_base
var subscription_id # u32
var max_interval # u16
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.subscription_id = val.findsubval(0)
self.max_interval = val.findsubval(2)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U4, self.subscription_id)
s.add_TLV(2, TLV.U2, self.max_interval)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.SubscribeResponseMessage = Matter_SubscribeResponseMessage
#################################################################################
# WriteRequestMessage class
#################################################################################
class Matter_WriteRequestMessage : Matter_IM_Message_base
var suppress_response # bool
var timed_request # bool
var write_requests # array of AttributeDataIB
var more_chunked_messages # bool
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.suppress_response = val.findsubval(0)
self.timed_request = val.findsubval(1)
self.write_requests = self.from_TLV_array(val.findsubval(2), matter.AttributeDataIB)
self.more_chunked_messages = val.findsubval(3)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.BOOL, self.suppress_response)
s.add_TLV(1, TLV.BOOL, self.timed_request)
self.to_TLV_array(s, 2, self.write_requests)
s.add_TLV(3, TLV.BOOL, self.more_chunked_messages)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.WriteRequestMessage = Matter_WriteRequestMessage
#################################################################################
# WriteResponseMessage class
#################################################################################
class Matter_WriteResponseMessage : Matter_IM_Message_base
var write_responses # array of AttributeStatusIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.write_requests = self.from_TLV_array(val.findsubval(0), matter.AttributeStatusIB)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
self.to_TLV_array(s, 0, self.write_responses)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.WriteResponseMessage = Matter_WriteResponseMessage
#################################################################################
# TimedRequestMessage class
#################################################################################
class Matter_TimedRequestMessage : Matter_IM_Message_base
var timeout # u16
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.timeout = val.findsubval(0)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.U2, self.timeout)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.TimedRequestMessage = Matter_TimedRequestMessage
#################################################################################
# InvokeRequestMessage class
#################################################################################
class Matter_InvokeRequestMessage : Matter_IM_Message_base
var suppress_response # bool
var timed_request # bool
var invoke_requests # array of CommandDataIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.suppress_response = val.findsubval(0)
self.timed_request = val.findsubval(1)
self.invoke_requests = self.from_TLV_array(val.findsubval(2), matter.CommandDataIB)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.BOOL, self.suppress_response)
s.add_TLV(1, TLV.BOOL, self.timed_request)
self.to_TLV_array(s, 2, self.invoke_requests)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.InvokeRequestMessage = Matter_InvokeRequestMessage
#################################################################################
# InvokeResponseMessage class
#################################################################################
class Matter_InvokeResponseMessage : Matter_IM_Message_base
var suppress_response # bool
var invoke_responses # array of InvokeResponseIB
# decode from TLV
def from_TLV(val)
if val == nil return nil end
self.suppress_response = val.findsubval(0)
self.invoke_responses = self.from_TLV_array(val.findsubval(1), matter.InvokeResponseIB)
return self
end
def to_TLV()
var TLV = matter.TLV
var s = TLV.Matter_TLV_struct()
s.add_TLV(0, TLV.BOOL, self.suppress_response)
self.to_TLV_array(s, 1, self.invoke_responses)
s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision)
return s
end
end
matter.InvokeResponseMessage = Matter_InvokeResponseMessage
#-
# Unit tests
import matter
m = matter.TLV.parse(bytes("1724020024033024040018"))
assert(m.tostring() == "[[2 = 0U, 3 = 48U, 4 = 0U]]")
#a = matter.IM.AttributePathIB().from_TLV(m)
a = matter.AttributePathIB().from_TLV(m)
assert(str(a) == "[00]0030/0000")
m = a.to_TLV()
assert(m.tostring() == "[[2 = 0U, 3 = 48U, 4 = 0U]]")
assert(m.encode() == bytes("1724020024033024040018"))
# create DataVersionFilterIB from scratch
c = matter.ClusterPathIB()
c.endpoint = 1
c.cluster = 32
c.to_TLV()
assert(str(c.to_TLV()) == "[[1 = 1U, 2 = 32U]]")
d = matter.DataVersionFilterIB()
d.path = c
d.data_version = 10
assert(str(d.to_TLV()) == '{0 = [[1 = 1U, 2 = 32U]], 1 = 10U}')
assert(d.to_TLV().encode() == bytes('1537002401012402201824010A18'))
# decode DataVersionFilterIB from scratch
m = matter.TLV.parse(bytes("1537002401012402201824010A18"))
assert(str(m) == '{0 = [[1 = 1U, 2 = 32U]], 1 = 10U}')
# ReadRequestMessage
m = matter.TLV.parse(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"))
assert(str(m) == "{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}")
r = matter.ReadRequestMessage().from_TLV(m)
assert(str(r) == "<Matter_ReadRequestMessage:{'attributes_requests': [[**]0031/FFFC, [00]0030/0000, [00]0030/0001, [00]0030/0002, [00]0030/0003, [00]0028/0002, [00]0028/0004, [**]0031/0003], 'data_version_filters': nil, 'event_filters': nil, 'event_requests': nil, 'fabric_filtered': false}>")
t = r.to_TLV()
assert(str(t) == "{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}")
# ReportDataMessage
r = matter.ReportDataMessage()
r.subscription_id = 1
r.attribute_reports = []
a1 = matter.AttributeReportIB()
a1.attribute_status = matter.AttributeStatusIB()
a1.attribute_status.path = matter.AttributePathIB()
a1.attribute_status.status = matter.StatusIB()
a1.attribute_status.path.endpoint = 0
a1.attribute_status.path.cluster = 0x0030
a1.attribute_status.path.attribute = 0
a1.attribute_status.status.status = 0
a1.attribute_status.status.cluster_status = 0
a1.attribute_data = matter.AttributeDataIB()
a1.attribute_data.data_version = 1
a1.attribute_data.path = matter.AttributePathIB()
a1.attribute_data.path.endpoint = 0
a1.attribute_data.path.cluster = 0x0030
a1.attribute_data.path.attribute = 0
a1.attribute_data.data = matter.TLV.create_TLV(matter.TLV.UTF1, "Tasmota")
assert(str(a1.to_TLV()) == '{0 = {0 = [[2 = 0U, 3 = 48U, 4 = 0U]], 1 = [[0 = 0U, 1 = 0U]]}, 1 = {0 = 1U, 1 = [[2 = 0U, 3 = 48U, 4 = 0U]], 2 = "Tasmota"}}')
r.attribute_reports.push(a1)
#{0 = 1U, 1 = [{0 = {0 = [[2 = 0U, 3 = 48U, 4 = 0U]], 1 = [[0 = 0U, 1 = 0U]]}, 1 = {0 = 1U, 1 = [[2 = 0U, 3 = 48U, 4 = 0U]], 2 = "Tasmota"}}]}
assert(r.to_TLV().encode() == bytes('1524000136011535003700240200240330240400183701240000240100181835012400013701240200240330240400182C02075461736D6F746118181818'))
# <Matter_AttributeReportIB:{
# 'attribute_data': <Matter_AttributeDataIB:{
# 'data': nil, 'data_version': nil, 'path': nil}>,
# 'attribute_status': <Matter_AttributeStatusIB:{
# 'path': [00]0030/0000, 'status': <Matter_StatusIB:{
# 'cluster_status': 0, 'status': 0}>}>}>
-#

View File

@ -0,0 +1,407 @@
#
# Matter_Message.be - suppport for Matter Message Packet/Frame structure, deconding, enconding, encryption & decryption
#
# 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_Frame,weak
# Matter frame format, see 4.4 (p. 107)
class Matter_Frame
# context information
var message_handler # the message handler instance that decodes and generate responses
var session # the session object associated, or `nil` if no session
# content of the message
var raw # raw bytes of the packet
var payload_idx # index in raw for beginning of payload
# Message header
var flags
var flag_s # Note: Matter booleans are 1/0 not true/false
var flag_dsiz
var local_session_id
var sec_flags
var sec_p
var sec_c
var sec_mx
var sec_sesstype
var message_counter
var source_node_id
var dest_node_id_2 # if 2 bytes
var dest_node_id_8 # if 8 bytes
# Message payload
var x_flags
var x_flag_v
var x_flag_sx
var x_flag_r
var x_flag_a
var x_flag_i
var opcode
var exchange_id
var protocol_id
var vendor_id # (opt)
var ack_message_counter # (opt)
var sec_extensions
# var
var app_payload_idx # index where the application payload starts
#############################################################
# keep track of the message_handler object
#
def init(message_handler, raw)
self.message_handler = message_handler
self.raw = raw
end
#############################################################
# decode the header of the message and provide session
# information if decryption is required
#
# returns `true` if ok, `false` if message needs to be ignored
# or raises an exception if something went wrong
def decode_header()
var idx = 0
var raw = self.raw
# flags
self.flags = raw.get(0, 1)
if (self.flags & 0xF8) != 0x00 return false end # ignore if Matter version if not 1.0
self.flag_s = raw.getbits(2, 1)
self.flag_dsiz = raw.getbits(0, 2)
if self.flag_dsiz == 3 return false end # ignore if dsiz is unknown
# security flagse
self.sec_flags = raw.get(3, 1)
self.sec_p = raw.getbits(3*8 + 7, 1)
self.sec_c = raw.getbits(3*8 + 6, 1)
self.sec_mx = raw.getbits(3*8 + 5, 1)
self.sec_sesstype = raw.getbits(3*8, 2)
if self.sec_sesstype > 1 return false end # ignore if session type is unknown
#
self.local_session_id = raw.get(1, 2)
self.message_counter = raw.get(4, 4)
idx += 8
# source node id?
if self.flag_s
self.source_node_id = raw[idx .. idx+7]
idx += 8
end
# dest node id?
if self.flag_dsiz == 1
self.dest_node_id_8 = raw[idx .. idx+7]
idx += 8
elif self.flag_dsiz == 2
self.dest_node_id_2 = raw.get(idx, 2)
idx += 2
end
# skip MX if any
if self.sec_mx
var sz = raw.get(idx, 2)
idx += sz + 2 # ignore bytes
end
self.payload_idx = idx
return true
end
#############################################################
def decode_payload()
var idx = self.payload_idx # retrieve index for payload
var raw = self.raw
# Message paylod
self.x_flags = raw.get(idx, 1)
# flags
self.x_flag_v = raw.getbits(idx*8 + 4, 1)
self.x_flag_sx = raw.getbits(idx*8 + 3, 1)
self.x_flag_r = raw.getbits(idx*8 + 2, 1)
self.x_flag_a = raw.getbits(idx*8 + 1, 1)
self.x_flag_i = raw.getbits(idx*8, 1)
self.opcode = raw.get(idx+1, 1)
self.exchange_id = raw.get(idx+2, 2)
self.protocol_id = raw.get(idx+4, 2)
idx += 6
# optional protocol vendor id
if self.x_flag_v
self.vendor_id = raw.get(idx, 2)
idx += 2
end
# optional Acknowledged Message Counter (32 bits)
if self.x_flag_a
self.ack_message_counter = raw.get(idx, 4)
idx += 4
end
# optional secure extensions
if self.x_flag_sx
var sz = raw.get(idx, 2)
idx += sz + 2 # skip
end
self.app_payload_idx = idx
return self
end
#############################################################
# Encode the packet as raw bytes
#
# If encryption is needed, it is done later
#
# Header is built from attributes
# `payload` is a bytes() buffer for the app payload
def encode(payload)
var raw = bytes()
# compute flags
if self.flags == nil
self.flags = 0x00
if self.flag_s self.flags = self.flags | 0x04 end
if self.flag_dsiz self.flags = self.flags | (self.flag_dsiz & 0x03) end
end
raw.add(self.flags, 1)
# local_session_id (mandatory)
raw.add(self.local_session_id ? self.local_session_id : 0, 2)
# compute security flags
if self.sec_flags == nil
self.sec_flags = 0x00
if self.sec_p self.sec_flags = self.sec_flags | 0x80 end
if self.sec_c self.sec_flags = self.sec_flags | 0x40 end
# if self.sec_mx self.sec_flags = self.sec_flags | 0x20 end # not supportedd
if self.sec_sesstype self.sec_flags = self.sec_flags | (self.sec_sesstype & 0x03) end
end
raw.add(self.sec_flags, 1)
#
raw.add(self.message_counter, 4) # mandatory
#
if self.flag_s raw .. self.source_node_id end # 8 bytes
if self.flag_dsiz == 0x01 raw .. self.dest_node_id_8 end # 8 bytes
if self.flag_dsiz == 0x02 raw.add(self.dest_node_id_2, 2) end # 2 bytes
# skip message extensions
self.payload_idx = size(raw)
# Message payload
if self.x_flags == nil
self.x_flags = 0x00
if self.x_flag_v self.x_flags = self.x_flags | 0x10 end
# if self.x_flag_sx self.x_flags = self.x_flags | 0x08 end # not implemented
if self.x_flag_r self.x_flags = self.x_flags | 0x04 end
if self.x_flag_a self.x_flags = self.x_flags | 0x02 end
if self.x_flag_i self.x_flags = self.x_flags | 0x01 end
end
raw.add(self.x_flags, 1)
# opcode (mandatory)
raw.add(self.opcode, 1)
raw.add(self.exchange_id, 2)
raw.add(self.protocol_id, 2)
if self.x_flag_a raw.add(self.ack_message_counter, 4) end
# finally payload
self.app_payload_idx = size(raw)
if payload
raw .. payload
end
self.debug(raw)
self.raw = raw
return raw
end
#############################################################
# Generate a Standalone Acknowledgment
# Uses `PROTOCOL_ID_SECURE_CHANNEL` no ecnryption required
def build_standalone_ack()
import string
# send back response
var resp = classof(self)(self.message_handler)
if self.flag_s
resp.flag_dsiz = 0x01
resp.dest_node_id_8 = self.source_node_id
else
resp.flag_dsiz = 0x00
end
resp.session = self.session # also copy the session object
# message counter
resp.message_counter = self.session.counter_snd.next()
resp.local_session_id = self.session.initiator_session_id
resp.x_flag_i = 0 # not sent by initiator
resp.opcode = 0x10 # MRP Standalone Acknowledgement
resp.exchange_id = self.exchange_id
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
tasmota.log(string.format("MTR: <Replied %s", matter.get_opcode_name(resp.opcode)), 2)
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)
import string
# send back response
var resp = classof(self)(self.message_handler)
if self.flag_s
resp.flag_dsiz = 0x01
resp.dest_node_id_8 = self.source_node_id
else
resp.flag_dsiz = 0x00
end
resp.session = self.session # also copy the session object
# message counter
# if self.session && self.session.initiator_session_id != 0
if self.local_session_id != 0 && self.session && self.session.initiator_session_id != 0
resp.message_counter = self.session.counter_snd.next()
resp.local_session_id = self.session.initiator_session_id
else
resp.message_counter = self.session._counter_insecure_snd.next()
resp.local_session_id = 0
end
resp.x_flag_i = 0 # not sent by initiator
resp.opcode = opcode
resp.exchange_id = self.exchange_id
resp.protocol_id = self.protocol_id
if self.x_flag_r
resp.x_flag_a = 1 # ACK of previous message
resp.ack_message_counter = self.message_counter
end
resp.x_flag_r = reliable ? 1 : 0
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)
end
return resp
end
#############################################################
# decrypt with I2S key
# return cleartext or `nil` if failed
def decrypt()
import crypto
var session = self.session
var raw = self.raw
# decrypt the message with `i2r` key
var i2r = session.get_i2r()
var mic = raw[-16..] # take last 16 bytes as signature
# use AES_CCM
var a = raw[0 .. self.payload_idx - 1]
var p = raw[self.payload_idx .. -17]
# recompute nonce
var n = bytes()
n.add(self.flags, 1)
n.add(self.message_counter, 4)
if self.source_node_id
n .. source_node_id
else
if session.peer_node_id
n .. session.peer_node_id
end
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)
# 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)
if tag != mic
tasmota.log("MTR: rejected packet due to invalid MIC", 3)
return nil
end
return cleartext
end
#############################################################
# encrypt with R2I key
# return true if ok
# changes the raw buffer in-place
def encrypt()
import crypto
var raw = self.raw
var session = self.session
# encrypt the message with `i2r` key
var r2i = session.get_r2i()
# use AES_CCM
var a = raw[0 .. self.payload_idx - 1]
var p = raw[self.payload_idx .. ]
# recompute nonce
var n = bytes()
n.add(self.flags, 1)
n.add(self.message_counter, 4)
if session.get_mode() == session.__CASE && session.deviceid
n .. session.deviceid
end
n.resize(13) # add zeros
tasmota.log("MTR: cleartext: " + self.raw.tohex(), 3)
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)
# 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)
# 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)
end
#############################################################
# Decode a message we are about to send, to ease debug
def debug(raw)
var r = matter.Frame(self.message_handler, raw)
r.decode_header()
r.decode_payload()
tasmota.log("MTR: sending decode: " + matter.inspect(r), 3)
end
end
matter.Frame = Matter_Frame

View File

@ -0,0 +1,171 @@
#
# Matter_MessageHandler.be - suppport for Matter Message handler, dispatches incoming messages and sends outgoing messages
#
# 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_MessageHandler,weak
class Matter_MessageHandler
# callback for sending messages
var device # `tansport.msg_send(raw:bytes() [,...]) -> bool` true if succeeded
# handlers
var commissioning
var im # handler for Interaction Model
# counters
var counter_rcv # Global Unencrypted Message Counter incoming
#############################################################
def init(device)
self.device = device
self.commissioning = matter.Commisioning_Context(self)
self.im = matter.IM(self)
self.counter_rcv = matter.Counter()
end
#############################################################
# Called when a message is received
#
# Find or create a session for the message
# and dispacth to appropriate handler
#
def msg_received(raw, addr, port)
import string
try
tasmota.log("MTR: MessageHandler::msg_received raw="+raw.tohex(), 4)
var frame = matter.Frame(self, raw)
var ok = frame.decode_header()
if !ok return false end
# do we need decryption?
if frame.local_session_id == 0 && frame.sec_sesstype == 0
#############################################################
### 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)
frame.session = session
# check if it's a duplicate
if !self.counter_rcv.validate(frame.message_counter, false)
tasmota.log(string.format("MTR: rejected duplicate unencrypted message = %i ref = %i", frame.message_counter, self.counter_rcv.val()), 3)
return false
end
if !frame.decode_payload() return false end
self.device.packet_ack(frame.ack_message_counter) # acknowledge packet
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)
end
self.commissioning.process_incoming(frame, addr, port)
return true
else
#############################################################
# encrypted message
tasmota.log(string.format("MTR: decode header: local_session_id=%i message_counter=%i", frame.local_session_id, frame.message_counter), 3)
var session = self.device.sessions.get_session_by_local_session_id(frame.local_session_id)
if session == nil
tasmota.log("MTR: unknown local_session_id "+str(frame.local_session_id), 3)
tasmota.log("MTR: frame="+matter.inspect(frame), 3)
return false
end
frame.session = session # keep a pointer of the session in the message
# check if it's a duplicate
if !session.counter_rcv.validate(frame.message_counter, true)
tasmota.log("MTR: rejected duplicate encrypted message = " + str(frame.message_counter) + " counter=" + str(session.counter_rcv.val()), 3)
return false
end
var cleartext = frame.decrypt()
if !cleartext return false end
# packet is good, put back content in raw
frame.raw = frame.raw[0 .. frame.payload_idx - 1] # remove encrypted payload
frame.raw .. cleartext # add cleartext
# 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)
self.device.packet_ack(frame.ack_message_counter) # acknowledge packet
# dispatch according to protocol_id
var protocol_id = frame.protocol_id
if protocol_id == 0x0000 # PROTOCOL_ID_SECURE_CHANNEL
# it should not be encrypted
tasmota.log("MTR: PROTOCOL_ID_SECURE_CHANNEL " + matter.inspect(frame), 3)
# if frame.opcode == 0x10
# end
return true
elif protocol_id == 0x0001 # PROTOCOL_ID_INTERACTION_MODEL
# dispatch to IM Protocol Messages
return self.im.process_incoming(frame, addr, port)
# -- 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
# tasmota.log("MTR: PROTOCOL_ID_BDX not yet handled", 2)
# return false # ignore for now TODO
# -- PROTOCOL_ID_USER_DIRECTED_COMMISSIONING is only used by devices, as a device we will not receive any
# elif protocol_id == 0x0003 # PROTOCOL_ID_USER_DIRECTED_COMMISSIONING
# tasmota.log("MTR: PROTOCOL_ID_USER_DIRECTED_COMMISSIONING not yet handled", 2)
# return false # ignore for now TODO
else
tasmota.log("MTR: ignoring unhandled protocol_id:"+str(protocol_id), 3)
return false
end
end
return true
except .. as e, m
tasmota.log("MTR: MessageHandler::msg_received exception: "+str(e)+";"+str(m))
import debug
debug.traceback()
return false
end
end
#############################################################
def send_response(raw, addr, port, id)
self.device.msg_send(raw, addr, port, id)
end
#############################################################
def add_session(local_session_id, initiator_session_id, i2r, r2i, ac, session_timestamp)
import string
# create session object
tasmota.log(string.format("MTR: add_session local_session_id=%i initiator_session_id=%i", local_session_id, initiator_session_id), 3)
var session = self.device.sessions.create_session(local_session_id, initiator_session_id)
session.set_keys(i2r, r2i, ac, session_timestamp)
end
#############################################################
# placeholder, nothing to run for now
def every_second()
self.commissioning.every_second()
self.im.every_second()
end
end
matter.MessageHandler = Matter_MessageHandler

View File

@ -0,0 +1,46 @@
#
# Matter_Module.be - implements the global `matter` module from a solidified module that can be dynamically enriched
#
# 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 module for extensibility
#
# this allows the module `matter` to be extended
var matter = module("matter")
def setmember(k, v)
import global
if !global.contains(".matter") global.(".matter") = {} end
global.(".matter")[k] = v
end
def member(k)
import global
import undefined
if global.contains(".matter") && global.(".matter").contains(k)
return global.(".matter")[k]
else
return undefined
end
end
matter.setmember = setmember
matter.member = member
#@ solidify:matter.setmember,weak
#@ solidify:matter.member,weak

View File

@ -0,0 +1,88 @@
#
# Matter_Plugin.be - generic superclass for all Matter plugins, used to define specific behaviors (light, switch, media...)
#
# 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 modules for extensibility
# template but not actually used
#@ solidify:Matter_Plugin,weak
class Matter_Plugin
var device
var endpoints
#############################################################
# Constructor
def init(device)
self.device = device
self.endpoints = []
end
#############################################################
# Which endpoints does it handle (list of numbers)
def get_endpoints()
return self.endpoints
end
#############################################################
# read attribute
def read_attribute(msg, endpoint, cluster, attribute)
return nil
end
#############################################################
# read event
# TODO
def read_event(msg, endpoint, cluster, eventid)
return nil
end
#############################################################
# subscribe attribute
# TODO
def subscribe_attribute(msg, endpoint, cluster, attribute)
return nil
end
#############################################################
# subscribe event
# TODO
def subscribe_event(msg, endpoint, cluster, eventid)
return nil
end
#############################################################
# write attribute
def write_attribute(msg, endpoint, cluster, attribute)
return nil
end
#############################################################
# invoke command
def invoke_request(msg, val, ctx)
return nil
end
#############################################################
# timed request
# TODO - should we even support this?
def timed_request(msg, val, ctx)
return nil
end
end
matter.Plugin = Matter_Plugin

View File

@ -0,0 +1,52 @@
#
# 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
#############################################################
# Constructor
def init(device)
super(self).init(device)
self.endpoints = [ 1 ]
end
#############################################################
# read an attribute
#
def read_attribute(msg, endpoint, cluster, attribute)
# no match found, return that the attribute is unsupported
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

@ -0,0 +1,372 @@
#
# Matter_Plugin_core.be - implements the core features that a Matter device must implemment
#
# 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_core,weak
class Matter_Plugin_core : Matter_Plugin
#############################################################
# Constructor
def init(device)
super(self).init(device)
self.endpoints = [ 0 ]
end
#############################################################
# read an attribute
#
def read_attribute(msg, endpoint, cluster, attribute)
var TLV = matter.TLV
if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ==========
if attribute == 0x0000 # ---------- 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
bci.add_TLV(1, TLV.U2, 900) # MaxCumulativeFailsafeSeconds
return bci
elif attribute == 0x0002 # ---------- RegulatoryConfig / RegulatoryLocationType ----------
return TLV.create_TLV(TLV.U1, 2) # 2 = IndoorOutdoor | esp-matter = 0
elif attribute == 0x0003 # ---------- LocationCapability / RegulatoryLocationType----------
return TLV.create_TLV(TLV.U1, 2) # 2 = IndoorOutdoor
elif attribute == 0x0004 # ---------- SupportsConcurrentConnection / bool ----------
return TLV.create_TLV(TLV.BOOL, false) # false - maybe can set to true
end
# ====================================================================================================
elif cluster == 0x0032 # ========== Diagnostic Logs Cluster 11.10 p.637 ==========
# no attributes
# ====================================================================================================
elif cluster == 0x0033 # ========== General Diagnostics Cluster 11.11 p.642 ==========
if attribute == 0x0000 # ---------- NetworkInterfaces ----------
var nwi = TLV.Matter_TLV_list() # TODO list network interfaces, empty list for now
return nwi
elif attribute == 0x0001 # ---------- RebootCount u16 ----------
return TLV.create_TLV(TLV.U2, tasmota.cmd("Status 1")['StatusPRM']['BootCount'])
elif attribute == 0x0002 # ---------- UpTime u16 ----------
return TLV.create_TLV(TLV.U4, tasmota.cmd("Status 11")['StatusSTS']['UptimeSec'])
# TODO add later other attributes
elif attribute == 0x0008 # ---------- TestEventTriggersEnabled bool ----------
return TLV.create_TLV(TLV.BOOL, false) # false - maybe can set to true
end
# ====================================================================================================
elif cluster == 0x0034 # ========== Software Diagnostics Cluster 11.12 p.654 ==========
# no mandatory attributes - to be added later (maybe)
# ====================================================================================================
elif cluster == 0x0038 # ========== Time Synchronization 11.16 p.689 ==========
if attribute == 0x0000 # ---------- UTCTime / epoch_us ----------
var epoch_us = int64(tasmota.rtc()['utc']) * int64(1000000)
return TLV.create_TLV(TLV.U8, epoch_us) # TODO test the conversion of int64()
elif attribute == 0x0001 # ---------- Granularity / enum ----------
return TLV.create_TLV(TLV.U1, 3) # MillisecondsGranularity (NTP every hour, i.e. 36ms max drift)
# TODO add some missing args
elif attribute == 0x0007 # ---------- LocalTime / epoch_us ----------
var epoch_us = int64(tasmota.rtc()['local']) * int64(1000000)
return TLV.create_TLV(TLV.U8, epoch_us) # TODO test the conversion of int64()
end
# ====================================================================================================
elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ==========
if attribute == 0x0000 # ---------- NOCs / list[NOCStruct] ----------
# TODO
elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ----------
# TODO
elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ----------
return TLV.create_TLV(TLV.U1, 5) # Max 5 fabrics
elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ----------
return TLV.create_TLV(TLV.U1, 1) # TODO
elif attribute == 0x0004 # ---------- TrustedRootCertificates / list[octstr] ----------
# TODO
elif attribute == 0x0005 # ---------- Current­ FabricIndex / u1 ----------
# TODO
end
# ====================================================================================================
elif cluster == 0x003C # ========== Administrator Commissioning Cluster 11.18 p.725 ==========
# TODO
# ====================================================================================================
elif cluster == 0x0028 # ========== Basic Information Cluster cluster 11.1 p.565 ==========
if attribute == 0x0000 # ---------- DataModelRevision / u16 ----------
return TLV.create_TLV(TLV.U2, 0)
elif attribute == 0x0001 # ---------- VendorName / string ----------
return TLV.create_TLV(TLV.UTF1, "Tasmota")
elif attribute == 0x0002 # ---------- VendorID / vendor-id ----------
return TLV.create_TLV(TLV.U2, self.device.vendorid) # Vendor ID reserved for development
elif attribute == 0x0003 # ---------- ProductName / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.cmd("DeviceName")['DeviceName'])
elif attribute == 0x0004 # ---------- ProductID / u16 (opt) ----------
return TLV.create_TLV(TLV.U2, 32768) # taken from esp-matter example
elif attribute == 0x0005 # ---------- NodeLabel / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.cmd("FriendlyName")['FriendlyName1'])
elif attribute == 0x0006 # ---------- Location / string ----------
return TLV.create_TLV(TLV.UTF1, "XX") # no location
elif attribute == 0x0007 # ---------- HardwareVersion / u16 ----------
return TLV.create_TLV(TLV.U2, 0)
elif attribute == 0x0008 # ---------- HardwareVersionString / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Hardware'])
elif attribute == 0x0009 # ---------- SoftwareVersion / u32 ----------
return TLV.create_TLV(TLV.U2, 0)
elif attribute == 0x000A # ---------- SoftwareVersionString / string ----------
return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Version'])
end
# ====================================================================================================
elif cluster == 0x003F # ========== Group Key Management Cluster 11.2 p.572 ==========
# TODO
# ====================================================================================================
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()
locl.add_TLV(nil, TLV.UTF1, tasmota.locale())
return locl
end
# ====================================================================================================
elif cluster == 0x002C # ========== Time Format Localization Cluster 11.4 p.581 ==========
if attribute == 0x0000 # ---------- HourFormat / HourFormat ----------
return TLV.create_TLV(TLV.U1, 1) # 1 = 24hr
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()
callist.add_TLV(nil, TLV.create_TLV(TLV.U1, 4))
return callist
end
# ====================================================================================================
elif cluster == 0x0031 # ========== Network Commissioning Cluster cluster 11.8 p.606 ==========
if attribute == 0x0003 # ---------- ConnectMaxTimeSeconds / uint8 ----------
return TLV.create_TLV(TLV.U1, 30) # 30 - value taking from example in esp-matter
elif attribute == 0xFFFC # ---------- FeatureMap / map32 ----------
return TLV.create_TLV(TLV.U4, 0) # 15s ??? TOOD what should we put here?
end
end
# no match found, return that the attribute is unsupported
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)
import crypto
var TLV = matter.TLV
var cluster = ctx.cluster
var command = ctx.command
var session = msg.session
if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ==========
if command == 0x0000 # ---------- ArmFailSafe ----------
# create ArmFailSafeResponse
# ID=1
# 0=ErrorCode (OK=0)
# 1=DebugText
var ExpiryLengthSeconds = val.findsubval(0, 900)
var Breadcrumb = val.findsubval(1, 0)
session.breadcrumb = Breadcrumb
var afsr = TLV.Matter_TLV_struct()
afsr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK
afsr.add_TLV(1, TLV.UTF1, "") # DebugText = ""
ctx.command = 0x01 # ArmFailSafeResponse
return afsr
elif command == 0x0002 # ---------- SetRegulatoryConfig ----------
var NewRegulatoryConfig = val.findsubval(0) # RegulatoryLocationType Enum
var CountryCode = val.findsubval(1, "XX")
var Breadcrumb = val.findsubval(2, 0)
session.breadcrumb = Breadcrumb
# create SetRegulatoryConfigResponse
# ID=1
# 0=ErrorCode (OK=0)
# 1=DebugText
var srcr = TLV.Matter_TLV_struct()
srcr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK
srcr.add_TLV(1, TLV.UTF1, "") # DebugText = ""
ctx.command = 0x03 # SetRegulatoryConfigResponse
return srcr
elif command == 0x0004 # ---------- CommissioningComplete p.636 ----------
# no data
session.breadcrumb = 0 # clear breadcrumb
session.set_no_expiration()
# create CommissioningCompleteResponse
# ID=1
# 0=ErrorCode (OK=0)
# 1=DebugText
var ccr = TLV.Matter_TLV_struct()
ccr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK
ccr.add_TLV(1, TLV.UTF1, "") # DebugText = ""
ctx.command = 0x05 # CommissioningCompleteResponse
self.device.start_commissioning_complete_deferred(session)
return ccr # trigger a standalone ack
end
elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ==========
if command == 0x0002 # ---------- CertificateChainRequest ----------
var CertificateType = val.findsubval(0) # CertificateChainType Enum 1=DACCertificate 2=PAICertificate
if CertificateType != 1 && CertificateType != 2
ctx.status = matter.UNSUPPORTED_COMMAND
return nil
end
# create CertificateChainResponse
# ID=1
# 0=Certificate (octstr)
var ccr = TLV.Matter_TLV_struct()
ccr.add_TLV(0, TLV.B2, CertificateType == 1 ? matter.DAC_Cert_FFF1_8000() : matter.PAI_Cert_FFF1()) # send DAC_Cert_FFF1_8000 or PAI_Cert_FFF1
ctx.command = 0x03 # CertificateChainResponse
return ccr
elif command == 0x0000 # ---------- AttestationRequest ----------
var AttestationNonce = val.findsubval(0) # octstr
if size(AttestationNonce) != 32 return nil end # check size on nonce
ctx.command = 0x01 # AttestationResponse
# build Attestation Elements 11.17.5.4 p.707
var att_elts = TLV.Matter_TLV_struct()
att_elts.add_TLV(1, TLV.B2, matter.CD_FFF1_8000()) # certification_declaration
att_elts.add_TLV(2, TLV.B1, AttestationNonce) # attestation_nonce
att_elts.add_TLV(3, TLV.U4, tasmota.rtc()['utc']) # timestamp in epoch-s
var attestation_message = att_elts.encode()
var ac = session.get_ac()
var attestation_tbs = attestation_message + ac
tasmota.log("MTR: attestation_tbs=" + attestation_tbs.tohex(), 3)
var attestation_signature = crypto.EC_P256().ecdsa_sign_sha256(matter.DAC_Priv_FFF1_8000(), attestation_tbs)
# create AttestationResponse
# 0=AttestationElements (octstr max 900 bytes)
# 1=AttestationSignature (octstr 64)
var ar = TLV.Matter_TLV_struct()
ar.add_TLV(0, TLV.B2, attestation_message) # AttestationElements
ar.add_TLV(1, TLV.B1, attestation_signature) # AttestationElements
ctx.command = 0x01 # AttestationResponse
return ar
elif command == 0x0004 # ---------- CSRRequest ----------
var CSRNonce = val.findsubval(0) # octstr 32
if size(CSRNonce) != 32 return nil end # check size on nonce
var IsForUpdateNOC = val.findsubval(1, false) # bool
var csr = session.gen_CSR()
var nocsr_elements = TLV.Matter_TLV_struct()
nocsr_elements.add_TLV(1, TLV.B2, csr)
nocsr_elements.add_TLV(2, TLV.B1, CSRNonce)
var nocsr_elements_message = nocsr_elements.encode()
# sign with attestation challenge
var nocsr_tbs = nocsr_elements_message + session.get_ac()
tasmota.log("MTR: nocsr_tbs=" + nocsr_tbs.tohex(), 3)
var attestation_signature = crypto.EC_P256().ecdsa_sign_sha256(matter.DAC_Priv_FFF1_8000(), nocsr_tbs)
# create CSRResponse
# 0=NOCSRElements (octstr max 900 bytes)
# 1=AttestationSignature (octstr 64)
var csrr = TLV.Matter_TLV_struct()
csrr.add_TLV(0, TLV.B2, nocsr_elements_message) # AttestationElements
csrr.add_TLV(1, TLV.B1, attestation_signature) # AttestationElements
ctx.command = 0x05 # CSRResponse
return csrr
elif command == 0x000B # ---------- AddTrustedRootCertificate ----------
var RootCACertificate = val.findsubval(0) # octstr 400 max
session.set_ca(RootCACertificate)
tasmota.log("MTR: received ca_root="+RootCACertificate.tohex(), 3)
ctx.status = matter.SUCCESS # OK
return nil # trigger a standalone ack
elif command == 0x0006 # ---------- AddNOC ----------
var NOCValue = val.findsubval(0) # octstr max 400
var ICACValue = val.findsubval(1) # octstr max 400
var IpkValue = val.findsubval(2) # octstr max 16
var CaseAdminSubject = val.findsubval(3)
var AdminVendorId = val.findsubval(4)
if session.get_ca() == nil
tasmota.log("MTR: Error: AdNOC without CA", 2)
return nil
end
session.set_noc(NOCValue, ICACValue)
session.set_ipk_epoch_key(IpkValue)
session.admin_subject = CaseAdminSubject
session.admin_vendor = AdminVendorId
# extract important information from NOC
var noc_cert = matter.TLV.parse(NOCValue)
var dnlist = noc_cert.findsub(6)
var fabric = dnlist.findsubval(21)
var deviceid = dnlist.findsubval(17)
if !fabric || !deviceid
tasmota.log("MTR: Error: no fabricid nor deviceid in NOC certificate", 2)
return false
end
# convert fo bytes(8)
if type(fabric) == 'int' fabric = int64(fabric).tobytes() else fabric = fabric.tobytes() end
if type(deviceid) == 'int' deviceid = int64(deviceid).tobytes() else deviceid = deviceid.tobytes() end
var root_ca = matter.TLV.parse(session.get_ca()).findsubval(9) # extract public key from ca
root_ca = root_ca[1..] # remove first byte as per Matter specification
var info = bytes().fromstring("CompressedFabric") # as per spec, 4.3.2.2 p.99
var hk = crypto.HKDF_SHA256()
var fabric_rev = fabric.copy().reverse()
var k_fabric = hk.derive(root_ca, fabric_rev, info, 8)
session.set_fabric_device(fabric, deviceid, k_fabric)
# move to next step
self.device.start_operational_dicovery_deferred(session)
# create NOCResponse
# 0=StatusCode
# 1=FabricIndex (1-254) (opt)
# 2=DebugText (opt)
var nocr = TLV.Matter_TLV_struct()
nocr.add_TLV(0, TLV.U1, matter.SUCCESS) # Status
nocr.add_TLV(1, TLV.U1, 1) # fabric-index
ctx.command = 0x08 # NOCResponse
return nocr
end
end
end
end
matter.Plugin_core = Matter_Plugin_core

View File

@ -0,0 +1,574 @@
#
# Matter_Session.be - Support for Matter Sessions and Session Store
#
# 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_Session,weak
#@ solidify:Matter_Session_Store,weak
#################################################################################
# Matter_Session class
#
# Session is refered by remote_session_id once a session is established
# It can also be retrived by `source_node_id` when `local_session_id` is 0
#
# By convention, names starting with `_` are not persisted
#################################################################################
class Matter_Session
static var __PASE = 1 # PASE authentication in progress
static var __CASE = 2 # CASE authentication in progress
var __store # reference back to session store
# mode for Session. Can be PASE=1, CASE=2, Established=10 none=0
var mode
# sesions
var local_session_id # id for the current local session, starts with 1
var initiator_session_id # id used to respond to the initiator
var session_timestamp # timestamp (UTC) when the session was created
var source_node_id # source node if bytes(8) (opt, used only when session is not established)
# session_ids when the session will be active
var _future_initiator_session_id
var _future_local_session_id
# counters
var counter_rcv # counter for incoming messages
var counter_snd # counter for outgoing messages
# non-session counters
var _counter_insecure_rcv # counter for incoming messages
var _counter_insecure_snd # counter for outgoing messages
# encryption keys and challenges
var i2rkey # key initiator to receiver (incoming)
var r2ikey # key receiver to initiator (outgoing)
var attestation_challenge # Attestation challenge
var peer_node_id
# breadcrumb
var breadcrumb # breadcrumb attribute for this session
# our own private key
var no_private_key # private key of the device certificate (generated at commissioning)
# NOC information
var root_ca_certificate # root certificate of the initiator
var noc # Node Operational Certificate in TLV Matter Certificate
var icac # Initiator CA Certificate in TLV Matter Certificate
var ipk_epoch_key # timestamp
# CASE
var resumption_id # bytes(16)
var shared_secret # ECDH shared secret used in CASE
# Information extracted from `noc`
var fabric # fabric identifier as bytes(8) little endian
var fabric_compressed # comrpessed fabric identifier, hashed with root_ca public key
var deviceid # our own device id bytes(8) little endian
# Admin info extracted from NOC/ICAC
var admin_subject
var admin_vendor
# Previous CASE messages for Transcript hash
var _Msg1, _Msg2
# Expiration
var _persist # do we persist this sessions or is it remporary
var expiration # if not `nil` the entry is removed after this timestamp
# Group Key Derivation
static var __GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable
#############################################################
def init(store, local_session_id, initiator_session_id)
self.__store = store
self.mode = 0
self.local_session_id = local_session_id
self.initiator_session_id = initiator_session_id
self.counter_rcv = matter.Counter()
self.counter_snd = matter.Counter()
self._counter_insecure_rcv = matter.Counter()
self._counter_insecure_snd = matter.Counter()
self.breadcrumb = int64()
end
#############################################################
# Close the current PASE/CASE session to be re-negociated
#
def close()
# close the PASE session, it will be re-opened with a CASE session
var persist_save = self._persist
self.local_session_id = self._future_local_session_id
self.initiator_session_id = self._future_initiator_session_id
self.source_node_id = nil
self.counter_rcv.reset()
self.counter_snd.reset()
self.i2rkey = nil
self.r2ikey = nil
self.attestation_challenge = nil
# clear any attribute starting with `_`
import introspect
for k : introspect.members(self)
var v = introspect.get(self, k)
if type(v) != 'function' && type(v) != 'instance' && k[0] == '_' && k[1] != '_'
self.(k) = nil
end
end
self._persist = persist_save
# self._future_initiator_session_id = nil
# self._future_local_session_id = nil
end
#############################################################
def set_mode(mode)
self.mode = mode
end
def set_keys(i2r, r2i, ac, st)
self.i2rkey = i2r
self.r2ikey = r2i
self.attestation_challenge = ac
self.session_timestamp = st
end
def set_ca(ca)
self.root_ca_certificate = ca
end
def set_noc(noc, icac)
self.noc = noc
self.icac = icac
end
def set_ipk_epoch_key(ipk_epoch_key)
self.ipk_epoch_key = ipk_epoch_key
end
def set_fabric_device(fabric, deviceid, fc)
self.fabric = fabric
self.deviceid = deviceid
self.fabric_compressed = fc
self.__store.remove_redundant_session(self)
end
def set_persist(p)
self._persist = bool(p)
end
#############################################################
def get_mode()
return self.mode
end
def get_i2r()
return self.i2rkey
end
def get_r2i()
return self.r2ikey
end
def get_ac()
return self.attestation_challenge
end
def get_ca()
return self.root_ca_certificate
end
def get_ca_pub()
if self.root_ca_certificate
var m = matter.TLV.parse(self.root_ca_certificate)
return m.findsubval(9)
end
end
def get_noc() return self.noc end
def get_icac() return self.icac end
def get_ipk_epoch_key() return self.ipk_epoch_key end
def get_fabric() return self.fabric end
def get_deviceid() return self.deviceid end
def get_fabric_compressed() return self.fabric_compressed end
#############################################################
# Generate a private key (or retrieve it)
def get_pk()
if !self.no_private_key
import crypto
self.no_private_key = crypto.random(32)
end
return self.no_private_key
end
#############################################################
# Operational Group Key Derivation, 4.15.2, p.182
def get_ipk_group_key()
if self.ipk_epoch_key == nil || self.fabric_compressed == nil return nil end
import crypto
var hk = crypto.HKDF_SHA256()
var info = bytes().fromstring(self.__GROUP_KEY)
var hash = hk.derive(self.ipk_epoch_key, self.fabric_compressed, info, 16)
return hash
end
#############################################################
# set absolute time for expiration
def set_no_expiration()
self.expiration = nil
end
#############################################################
# set absolute time for expiration
def set_expire_time(t)
self.expiration = int(t)
end
#############################################################
# set relative time in the future for expiration (in seconds)
def set_expire_in_seconds(s, now)
if s == nil return end
if now == nil now = tasmota.rtc()['utc'] end
self.set_expire_time(now + s)
end
#############################################################
# set relative time in the future for expiration (in seconds)
# returns `true` if expiration date has been reached
def has_expired(now)
if now == nil now = tasmota.rtc()['utc'] end
if self.expiration != nil
return now >= self.expiration
end
return false
end
#############################################################
# to_json()
#
# convert a single entry as json
# returns a JSON string
#############################################################
def tojson()
import json
import string
import introspect
var keys = []
for k : introspect.members(self)
var v = introspect.get(self, k)
if type(v) != 'function' && k[0] != '_' keys.push(k) end
end
keys = matter.sort(keys)
var r = []
for k : keys
var v = introspect.get(self, k)
if v == nil continue end
if k == "counter_rcv" v = v.val()
elif k == "counter_snd" v = v.val() + 256 # take a margin to avoid reusing the same counter
end
if isinstance(v, bytes) v = "$$" + v.tob64() end # bytes
# if isinstance(v, bytes) v = "0x" + v.tohex() end
# if type(v) == 'string' v = string.escape(v, true) end
r.push(string.format("%s:%s", json.dump(str(k)), json.dump(v)))
end
return "{" + r.concat(",") + "}"
end
#############################################################
# fromjson()
#
# reads a map and load arguments
# returns an new instance of session
#############################################################
static def fromjson(store, values)
import string
import introspect
var self = matter.Session(store)
for k:values.keys()
var v = values[k]
if k == "counter_rcv" self.counter_rcv.reset(int(v))
elif k == "counter_snd" self.counter_snd.reset(int(v))
else
# standard values
if type(v) == 'string'
if string.find(v, "0x") == 0 # treat as bytes
introspect.set(self, k, bytes().fromhex(v[2..]))
elif string.find(v, "$$") == 0 # treat as bytes
introspect.set(self, k, bytes().fromb64(v[2..]))
else
introspect.set(self, k, v)
end
else
introspect.set(self, k, v)
end
end
end
return self
end
#############################################################
# Callback to Session store
def save()
self.__store.save()
end
#############################################################
def gen_CSR()
# Create CSR
# See 6.4.7. Node Operational Certificate Signing Request (NOCSR) p.302
var pk = self.get_pk() # private key of device
# Example
# 3081CA
# 3070020100300E310C300A060355040A0C034353523059301306072A8648CE3D020106082A8648CE3D030107
# PubKey=034200.043AEFB8D1F25813BE355920577971814827B24F2784A729297F88FBD998A59D29D439604678C42D2FA5DE4E9402C30376015E05DF0AD4A8737DCD4E6D03B11CF5
# A000
# 300C06082A8648CE3D0403020500
# 034800
# ECDSA=3045022054907C4F096B30EFEB56190E0F2AFAEE447991C927003185AD044D1A971BDEDD02210088FB7E44116FBD7DE5277890A3F3BC26ACC35441DF04FD0BBF02A369E751241D
import crypto
var ec256 = crypto.EC_P256()
var pub = ec256.public_key(pk)
var seg1 = bytes("3070020100300E310C300A060355040A0C034353523059301306072A8648CE3D020106082A8648CE3D030107034200")
seg1 .. pub
seg1 .. bytes("A000")
var seg2 = bytes("300C06082A8648CE3D0403020500") # not mutable
# compute signature in ECDSA format
var sig = ec256.ecdsa_sign_sha256_asn1(pk, seg1)
var seg3 = bytes(128)
seg3.add(0x03, 1)
seg3.add(size(sig)+1, 1)
seg3.add(0x00, 1)
seg3 .. sig
# construct the global csr
var seg_123_size = size(seg1) + size(seg2) + size(seg3)
var csr = bytes(208)
csr.add(0x30, 1)
csr.add(0x81, 1)
csr.add(seg_123_size & 0xFF, 1)
csr .. seg1
csr .. seg2
csr .. seg3
return csr
end
end
matter.Session = Matter_Session
#################################################################################
# Matter_Session_Store class
#################################################################################
class Matter_Session_Store
var sessions
static var FILENAME = "_matter_sessions.json"
#############################################################
def init()
self.sessions = []
end
#############################################################
# add session
def create_session(local_session_id, initiator_session_id)
var session = self.get_session_by_local_session_id(local_session_id)
if session != nil self.remove_session(session) end
session = matter.Session(self, local_session_id, initiator_session_id)
self.sessions.push(session)
return session
end
#############################################################
# add session
def add_session(s, expires_in_seconds)
if expires_in_seconds != nil
s.set_expire_in_seconds(expires_in_seconds)
end
self.sessions.push(s)
end
#############################################################
def get_session_by_local_session_id(id)
if id == nil return nil end
var sz = size(self.sessions)
var i = 0
var sessions = self.sessions
while i < sz
if sessions[i].local_session_id == id return sessions[i] end
i += 1
end
end
#############################################################
def get_session_by_source_node_id(nodeid)
if nodeid == nil return nil end
var sz = size(self.sessions)
var i = 0
var sessions = self.sessions
while i < sz
if sessions[i].source_node_id == nodeid return sessions[i] end
i += 1
end
end
#############################################################
# Remove session by reference
#
def remove_session(s)
var i = 0
var sessions = self.sessions
while i < size(self.sessions)
if sessions[i] == s
sessions.remove(i)
else
i += 1
end
end
end
#############################################################
# Remove session by reference
#
# remove all other sessions that have the same:
# fabric / deviceid / fc
def remove_redundant_session(s)
var i = 0
var sessions = self.sessions
while i < size(self.sessions)
var session = sessions[i]
if session != s && session.fabric == s.fabric && session.deviceid == s.deviceid #- && session.fabric_compressed == s.fabric_compressed -#
sessions.remove(i)
else
i += 1
end
end
end
#############################################################
# Generate a new local_session_id
def gen_local_session_id()
import crypto
while true
var candidate_local_session_id = crypto.random(2).get(0, 2)
if self.get_session_by_local_session_id(candidate_local_session_id) == nil
return candidate_local_session_id
end
end
end
#############################################################
# remove_expired
#
# Check is any session has expired
def remove_expired()
var dirty = false
var i = 0
var sessions = self.sessions
while i < size(self.sessions)
if sessions[i].has_expired()
if sessions[i]._persist dirty = true end # do we need to save
sessions.remove(i)
else
i += 1
end
end
if dirty self.save() end
end
def every_second()
self.remove_expired()
end
#############################################################
# find or create a session for unencrypted traffic
# expires in `expire` seconds
def find_session_source_id_unsecure(source_node_id, expire)
var session = self.get_session_by_source_node_id(source_node_id)
if session == nil
session = matter.Session(self, 0, 0)
session.source_node_id = source_node_id
self.sessions.push(session)
end
session.set_expire_in_seconds(expire)
return session
end
#############################################################
def save()
import json
self.remove_expired() # clean before saving
var j = []
for v:self.sessions
if v._persist
j.push(v.tojson())
end
end
var j_size = size(j)
j = "[" + j.concat(",") + "]"
try
import string
var f = open(self.FILENAME, "w")
f.write(j)
f.close()
tasmota.log(string.format("MTR: Saved %i session(s)", j_size), 2)
return j
except .. as e, m
tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2)
return j
end
end
#############################################################
def load()
import string
try
self.sessions = [] # remove any left-over
var f = open(self.FILENAME)
var s = f.read()
f.close()
import json
var j = json.load(s)
s = nil
tasmota.gc() # clean-up a potential long string
for v:j # iterate on values
var session = matter.Session.fromjson(self, v)
if session != nil
self.add_session(session)
end
end
tasmota.log(string.format("MTR: Loaded %i session(s)", size(self.sessions)), 2)
except .. as e, m
if e != "io_error"
tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2)
end
end
self.remove_expired() # clean after load
end
end
matter.Session_Store = Matter_Session_Store
#-
# Unit test
var s = Matter_Session(1,2)
s.counter_rcv.validate(0x100, false)
s.counter_snd.validate(0x1000, false)
s.source_node_id = bytes("1122334455667788")
assert(s.tojson() == '{"breadcrumb":"0","counter_rcv":256,"counter_snd":4352,"initiator_session_id":2,"local_session_id":1,"source_node_id":"0x1122334455667788"}')
var ss = Matter_Session_Store()
ss.add_session(s)
var j = ss.save()
assert(j == '{"1":{"breadcrumb":"0","counter_rcv":256,"counter_snd":4352,"initiator_session_id":2,"local_session_id":1,"source_node_id":"0x1122334455667788"}}')
var ss = Matter_Session_Store()
ss.load()
-#

View File

@ -0,0 +1,874 @@
#
# Matter_TLV.be - implements the encoding and decoding of Matter TLV structures (Tag/Lenght/Value) Appendix A.
#
# 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/>.
#
# Support for Matter Protocol: TLV encoding and decoding
import matter
#@ solidify:Matter_TLV.Matter_TLV_item,weak
#@ solidify:Matter_TLV.Matter_TLV_list,weak
#@ solidify:Matter_TLV.Matter_TLV_struct,weak
#@ solidify:Matter_TLV.Matter_TLV_array,weak
#@ solidify:Matter_TLV,weak
class Matter_TLV
static var _type = [
'i1', 'i2', 'i4', 'i8', 'u1', 'u2', 'u4', 'u8', # signed and unsigned 0x00-0x07
'bool', 'bool', 'float', 'double', # 0x08-0x0B
'UTF1', 'UTF2', 'UTF4', 'UTF8', # 0x0C-0x0F
'b1', 'b2', 'b4', 'b8', # 0x10-0x13
'null', 'struct', 'array', 'list', 'end' # 0x14-0x18
# all other are reserved
]
static var _len = [
1, 2, 4, 8, 1, 2, 4, 8,
0, 0, 4, 8,
-1, -2, -4, -8,
-1, -2, -4, -8,
0, -99, -99, -99, 0
]
# type values (enum like)
static var I1 = 0x00
static var I2 = 0x01
static var I4 = 0x02
static var I8 = 0x03
static var U1 = 0x04
static var U2 = 0x05
static var U4 = 0x06
static var U8 = 0x07
static var BOOL = 0x08 # when encoding, use indifferentiate
static var BFALSE = 0x08
static var BTRUE = 0x09
static var FLOAT = 0x0A
static var DOUBLE = 0x0B
static var UTF1 = 0x0C
static var UTF2 = 0x0D
static var UTF4 = 0x0E
static var UTF8 = 0x0F
static var B1 = 0x10
static var B2 = 0x11
static var B4 = 0x12
static var B8 = 0x13
static var NULL = 0x14
static var STRUCT = 0x15
static var ARRAY = 0x16
static var LIST = 0x17
static var EOC = 0x18
#################################################################################
# Matter_TLV_item class
#################################################################################
static class Matter_TLV_item
# we keep a shortcut reference to the Matter_TLV class
static var TLV = Matter_TLV
# parent tag to inherit vendor/profile/tag
var parent
var next_idx # next idx in buffer (when parsing)
# tags
var tag_vendor # 16 bit VendorID [opt]
var tag_profile # 16 bit profile number [opt]
var tag_number # 32 bit tag number
var tag_sub # context specific tag 8 bit [opt]
# type
var typ # TLV type number, set at decoding, mandatory for encoding
# value
var val # multi-type: int, float, bool, bytes, map, list
#############################################################
# constructor
def init(parent)
self.parent = parent
end
#############################################################
# neutral converter
def to_TLV()
return self
end
#############################################################
# create simple TLV
static def create_TLV(t, value)
if value != nil
var v = _class() # parent is nil
v.typ = t
v.val = value
return v
end
end
#############################################################
# tostring
#
# We are trying to follow the official Matter way of printing TLV
# Ex: '42U' or '1 = 42U' or '0xFFF1::0xDEED:0xAA55FEED = 42U'
def tostring()
import string
# var s = "<instance: Matter_TLV_item("
var s = ""
try # any exception raised in `tostring()` causes a crash, so better catch it here
if self.tag_profile == -1
s += "Matter::"
if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end
else
if self.tag_vendor != nil s += string.format("0x%04X::", self.tag_vendor) end
if self.tag_profile != nil s += string.format("0x%04X:", self.tag_profile) end
if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end
if self.tag_sub != nil s += string.format("%i ", self.tag_sub) end
end
if size(s) > 0 s += "= " end
# print value
if type(self.val) == 'int' s += string.format("%i", self.val)
if self.typ >= self.TLV.U1 && self.typ <= self.TLV.U8 s += "U" end
elif type(self.val) == 'bool' s += self.val ? "true" : "false"
elif self.val == nil s += "null"
elif type(self.val) == 'real' s += string.format("%g", self.val)
elif type(self.val) == 'string' s += string.format('"%s"', self.val)
elif isinstance(self.val, int64) s += self.val.tostring()
if self.typ >= self.TLV.U1 && self.typ <= self.TLV.U8 s += "U" end
elif type(self.val) == 'instance'
s += string.format("%s", self.val.tohex())
end
except .. as e, m
return e + " " + m
end
return s
end
#############################################################
# parse a bytes() array from `idx`
# args:
# b: bytes() buffer
# idx: starting index in the bytes() buffer
# parent: (optional) the parent object to inherit tag values
#
# returns the next `idx` for the item following or `-1` if error
# The next `idx` is also stored in `self.next_idx`
def parse(b, idx)
var item_type = self.typ
# parse LV
var TLV = self.TLV # cache value in register
var item_len = TLV._len[item_type]
if item_len == 8 # i64 / u64 / double
self.val = int64()
self.val.frombytes(b, idx)
idx += 8
elif item_type == TLV.BFALSE || item_type == TLV.BTRUE # bool
self.val = (item_type == TLV.BTRUE)
elif item_type < TLV.U8 # i1/i2/i4 u1/u2/u4
self.val = item_type <= TLV.I8 ? b.geti(idx, item_len) : b.get(idx, item_len)
idx += item_len
elif item_type == TLV.FLOAT # float
self.val = b.getfloat(idx)
idx += 4
elif item_len >= -8 && item_len <= -1 # len prefix 1/2/4/8
# TODO skip len == 8 for now
var b_len = b.get(idx, -item_len)
idx += -item_len
self.val = b[idx .. idx + b_len - 1]
idx += b_len
if (item_type <= TLV.UTF8) self.val = self.val.asstring() end
elif item_type == TLV.NULL # null
# do nothing
elif item_type == TLV.EOC
tasmota.log("MTR: unexpected eoc", 3)
else
tasmota.log("MTR: unexpected type: " + str(item_type), 3)
end
self.next_idx = idx
return idx
end
#############################################################
# encode TLV
#
# appends to the bytes() object
def encode(b)
var TLV = self.TLV
if b == nil b = bytes() end # start new buffer if none passed
# 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
self._encode_tag(b)
# encode value
if self.typ == TLV.I1 || self.typ == TLV.U1
b.add(int(self.val), 1)
elif self.typ == TLV.I2 || self.typ == TLV.U2
b.add(int(self.val), 2)
elif self.typ == TLV.I4 || self.typ == TLV.U4
b.add(int(self.val), 4)
elif self.typ == TLV.I8 || self.typ == TLV.U8
var i64 = self.val
if !isinstance(i64, int64)
i64 = int64(int(self.val))
end
b .. i64.tobytes()
elif self.typ == TLV.BFALSE || self.typ == TLV.BTRUE
# push nothing
elif self.typ == TLV.FLOAT
var idx = size(b)
b.add(0, 4)
b.setfloat(idx, real(self.val))
elif self.typ == TLV.DOUBLE
raise "value_error", "Unsupported type TLV.DOUBLE"
elif self.typ == TLV.UTF1
if size(self.val) > 255 raise "value_error", "string too big" end
b.add(size(self.val), 1)
b..bytes().fromstring(str(self.val))
elif self.typ == TLV.UTF2
if size(self.val) > 65535 raise "value_error", "string too big" end
b.add(size(self.val), 2)
b..bytes().frostring(str(self.val))
elif self.typ == TLV.B1
if size(self.val) > 255 raise "value_error", "bytes too big" end
b.add(size(self.val), 1)
b..self.val
elif self.typ == TLV.B2
if size(self.val) > 65535 raise "value_error", "bytes too big" end
b.add(size(self.val), 2)
b..self.val
elif self.typ == TLV.NULL
# push nothing
else
raise "value_error", "unsupported type " + str(self.typ)
end
return b
end
#############################################################
# internal_function
# encode Tag+Type as the first bytes
def _encode_tag(b)
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
b.add(0xE0 + self.typ, 1)
b.add(self.tag_vendor, 2)
b.add(self.tag_profile, 2)
b.add(self.tag_number, 4)
else
b.add(0xC0 + self.typ, 1)
b.add(self.tag_vendor, 2)
b.add(self.tag_profile, 2)
b.add(self.tag_number, 2)
end
elif self.tag_profile == -1 # Matter Common profile
if tag_huge
b.add(0x60 + self.typ, 1)
b.add(self.tag_number, 4)
else
b.add(0x40 + self.typ, 1)
b.add(self.tag_number, 2)
end
elif self.tag_profile != nil
if tag_huge
b.add(0xA0 + self.typ, 1)
b.add(self.tag_number, 4)
else
b.add(0x80 + self.typ, 1)
b.add(self.tag_number, 2)
end
elif self.tag_sub != nil
b.add(0x20 + self.typ, 1)
b.add(self.tag_sub, 1)
else # anonymous tag
b.add(0x00 + self.typ, 1)
end
end
#############################################################
# Compare the value index with an element
# returns:
# 1 if self is strictly greater than k
# 0 if equal or lower
def _cmp_gt(k)
# compare tag_vendor
if self.tag_vendor != nil
if k.tag_vendor == nil return 1 end
if self.tag_vendor > k.tag_vendor return 1 end
if self.tag_vendor == k.tag_vendor
if self.tag_profile > k.tag_profile return 1 end
end
# continue to tag comparison
end
# Matter common profile
if self.tag_profile == -1
if k.tag_profile == nil return 1 end
elif self.tag_profile == nil
if k.tag_profile == -1 return 0 end
end
if self.tag_number != nil
if k.tag_number == nil return 1 end
if self.tag_number > k.tag_number return 1 end
return 0
end
if self.tag_sub != nil
if k.tag_sub == nil return 1 end
if self.tag_sub > k.tag_sub return 1 end
end
return 0
end
#################################################################################
# Simple insertion sort - sorts the list in place, and returns the list
#################################################################################
static def sort(l)
# insertion sort
for i:1..size(l)-1
var k = l[i]
var j = i
while (j > 0) && (l[j-1]._cmp_gt(k) > 0)
l[j] = l[j-1]
j -= 1
end
l[j] = k
end
return l
end
#############################################################
# set parent
def set_parent(parent)
self.parent = parent
end
#############################################################
# Setters for tags
def set_fulltag(vendor, profile, tag)
self.tag_vendor = int(vendor)
self.tag_profile = int(profile)
self.tag_number = int(tag)
self.tag_sub = nil
end
# set context specific
def set_anonymoustag()
self.set_fulltag()
end
# set common profile
def set_commonprofile()
self.set_fulltag(nil, -1, nil)
end
# set context specific
def set_contextspecific(n)
self.set_fulltag()
self.tag_sub = int(n)
end
end
# class Matter_TLV_array var _ end
# class Matter_TLV_struct var _ end
static class Matter_TLV_list : Matter_TLV_item
#################################################################################
def init(parent)
super(self).init(parent)
self.typ = self.TLV.LIST
self.val = []
end
#################################################################################
def tostring()
return self.tostring_inner(false, "[[", "]]")
end
def tostring_inner(sorted, pre, post)
import string
var s = ""
try
if self.tag_profile == -1
s += "Matter::"
if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end
else
if self.tag_vendor != nil s += string.format("0x%04X::", self.tag_vendor) end
if self.tag_profile != nil s += string.format("0x%04X:", self.tag_profile) end
if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end
if self.tag_sub != nil s += string.format("%i ", self.tag_sub) end
end
if size(s) > 0 s += "= " end
s += pre
# sort values
var val_list = self.val.copy()
if sorted
self.sort(val_list)
end
s += val_list.concat(", ")
s += post
except .. as e, m
return e + " " + m
end
return s
end
#################################################################################
def parse(b, idx)
# iterate until end of struct
while b[idx] != self.TLV.EOC
# read next
var item = self.TLV.parse(b, idx, self)
idx = item.next_idx
self.val.push(item)
end
idx += 1
self.next_idx = idx
return idx
end
#############################################################
# encode TLV
#
# appends to the bytes() object
def _encode_inner(b, is_struct)
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
self.sort(val_list)
end
# output each one after the other
for v : val_list
v.encode(b)
end
# add 'end of container'
b.add(self.TLV.EOC, 1)
return b
end
#############################################################
def encode(b)
return self._encode_inner(b, false)
end
#############################################################
# Getters
#
# get by index
def item(n)
return self.val[n]
end
def setitem(n, v)
self.val[n] = v
end
def push(v)
self.val.push(v)
end
def size()
return size(self.val)
end
#############################################################
# get by sub-tag, return nil if not found
def findsub(n, v)
for k : self.val
if k.tag_sub == n return k end
end
return v
end
def findsubval(n, v)
var r = self.findsub(n)
if r != nil return r.val end
return v
end
def findsubtyp(n)
var r = self.findsub(n)
if r != nil return r.typ end
return nil
end
def getsub(n)
var v = self.findsub(n)
if v == nil raise "value_error", "sub not found" end
return v
end
def getsubval(n)
return self.getsub(n).val
end
#############################################################
# adders
def add_TLV(tag, t, value)
if value != nil
var v = self.TLV.Matter_TLV_item(self)
v.tag_sub = tag
v.typ = t
v.val = value
self.val.push(v)
end
return self
end
# add on object that implements `to_TLV()` and adds to the current container
#
# obj can be `nil`, in such case nothing happens
# returns `self` to allow calls to be chained
def add_obj(tag, obj)
if obj != nil
var value = obj.to_TLV()
value.tag_sub = tag
self.val.push(value)
end
return self
end
def add_list(tag)
var s = self.TLV.Matter_TLV_list(self)
s.tag_sub = tag
self.val.push(s)
return s
end
def add_array(tag)
var s = self.TLV.Matter_TLV_array(self)
s.tag_sub = tag
self.val.push(s)
return s
end
def add_struct(tag)
var s = self.TLV.Matter_TLV_struct(self)
s.tag_sub = tag
self.val.push(s)
return s
end
end
#################################################################################
# Matter_TLV_struct class
#################################################################################
static class Matter_TLV_struct : Matter_TLV_list
def init(parent)
super(self).init(parent)
self.typ = self.TLV.STRUCT
self.val = []
end
#############################################################
def tostring()
return self.tostring_inner(true, "{", "}")
end
#############################################################
# encode TLV
#
# appends to the bytes() object
def encode(b)
return self._encode_inner(b, true)
end
end
#################################################################################
# Matter_TLV_array class
#################################################################################
static class Matter_TLV_array : Matter_TLV_list
def init(parent)
super(self).init(parent)
self.typ = self.TLV.ARRAY
self.val = []
end
#############################################################
def tostring()
return self.tostring_inner(false, "[", "]")
end
#############################################################
def parse(b, idx)
# iterate until end of struct
while b[idx] != self.TLV.EOC
# read next
var item = self.TLV.parse(b, idx, self)
idx = item.next_idx
# for arrays, all tags must be anonymous
item.tag_vendor = nil
item.tag_profile = nil
item.tag_number = nil
item.tag_sub = nil
self.val.push(item)
end
idx += 1
self.next_idx = idx
return idx
end
end
#################################################################################
# bookkeeping
#################################################################################
# Matter_TLV.Matter_TLV_item = Matter_TLV_item
# Matter_TLV.Matter_TLV_struct = Matter_TLV_struct
# Matter_TLV.Matter_TLV_array = Matter_TLV_array
# Matter_TLV.Matter_TLV_list = Matter_TLV_list
# parse a bytes() array from `idx`
# args:
# b: bytes() buffer
# idx: starting index in the bytes() buffer
# parent: (optional) the parent object to inherit tag values
# returns the next `idx` for the item following or `-1` if error
static def parse(b, idx, parent)
var TLV = _class
if idx == nil idx = 0 end
# read type and tag_control
var item_type = b[idx] & 0x1F # values 0x00 - 0x1F
var item_tag_control = b[idx] & 0xE0 # values 0x20 - 0xE0
idx += 1 # skip tag/type byte
if (item_type > TLV.EOC) raise "TLV_error", "invalid TLV type "+str(item_type) end
# ############################################################
# instanciate TLV item or struct
var item
if item_type == TLV.STRUCT
item = _class.Matter_TLV_struct(parent)
elif item_type == TLV.ARRAY
item = _class.Matter_TLV_array(parent)
elif item_type == TLV.LIST
item = _class.Matter_TLV_list(parent)
else
item = _class.Matter_TLV_item(parent)
end
item.typ = item_type # set type for item
# ############################################################
# parse Tag and length
# do we have a vendor?
if item_tag_control == 0xC0 || item_tag_control == 0xE0
item.tag_vendor = b.get(idx, 2)
item.tag_profile = b.get(idx + 2, 2)
idx += 4
end
# Common profile tags
if item_tag_control == 0x40 || item_tag_control == 0x60
item.tag_vendor = nil
item.tag_profile = -1
end
# Tags
if item_tag_control == 0x00
# pass
elif item_tag_control == 0x20
# context specific tag
item.tag_sub = b[idx]
idx += 1
elif item_tag_control == 0xC0 || item_tag_control == 0x80 || item_tag_control == 0x40
item.tag_number = b.get(idx, 2)
idx += 2
else
item.tag_number = b.get(idx, 4)
idx += 4
end
# ############################################################
# parse Value
idx = item.parse(b, idx)
return item
end
#############################################################
# create simple TLV
static def create_TLV(t, value)
return _class.Matter_TLV_item.create_TLV(t, value)
end
end
# add to matter
import matter
matter.TLV = Matter_TLV
#-
# Test
import matter
#load("Matter_TLV.be")
var m
m = matter.TLV.parse(bytes("2502054C"))
assert(m.tostring() == "2 = 19461U")
assert(m.encode() == bytes("2502054C"))
m = matter.TLV.parse(bytes("0001"))
assert(m.tostring() == "1")
assert(m.encode() == bytes("0001"))
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"))
# 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"))
# 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"))
# 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"))
# 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"))
# 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"))
# 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"))
-#

View File

@ -0,0 +1,187 @@
#
# Matter_UDPServer.be - implements IPv6 UDP communication for Matter
#
# 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_UDPServer class
#
# For receiving and outgoing messages on UDP
#
import matter
#@ solidify:Matter_UDPPacket_sent,weak
#@ solidify:Matter_UDPServer,weak
#################################################################################
# Matter_UDPPacket_sent class
#
# A packet that needs to be resent if not acknowledged by the other party
#################################################################################
class Matter_UDPPacket_sent
static var RETRY_MS = 500 # retry every 500 ms
static var RETRIES = 4 # retry every 500 ms
var raw # bytes() to be sent
var addr # ip_address (string)
var port # port (int)
var msg_id # (int) message identifier that needs to be acknowledged
var retries # how many retries are allowed, when `0` drop and log
var next_try # timestamp (millis) when to try again
def init(raw, addr, port, id)
self.raw = raw
self.addr = addr
self.port = port
self.msg_id = id
self.retries = self.RETRIES
self.next_try = tasmota.millis() + self.RETRY_MS
end
def send(udp_socket)
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)
else
tasmota.log(string.format("MTR: failed to send packet to '[%s]:%i'", self.addr, self.port), 2)
end
end
end
matter.UDPPacket_sent = Matter_UDPPacket_sent
#################################################################################
# Matter_UDPServer class
#
#################################################################################
class Matter_UDPServer
static var MAX_PACKETS_READ = 4 # read at most 4 packets per tick
var address, port # local address and port
var listening # true if active
var udp_socket
var dispatch_cb # callback to call when a message is received
var packets_sent # map of packets sent to be acknowledged
#############################################################
def init(address, port)
self.address = address ? address : ""
self.port = port ? port : 5540
self.listening = false
self.packets_sent = {}
end
#############################################################
# start the server
# raises an exception if something is wrong
# registers as device handle
#
# `cb`: callback to call when a message is received
def start(cb)
if !self.listening
self.udp_socket = udp()
var ok = self.udp_socket.begin(self.address, self.port)
if !ok raise "network_error", "could not open UDP server" end
self.listening = true
self.dispatch_cb = cb
tasmota.add_driver(self)
end
end
#############################################################
# stop the server
# remove driver
def stop()
if self.listening
self.udp_socket.stop()
self.listening = false
tasmota.remove_driver(self)
end
end
#############################################################
def every_50ms()
import string
var packet_read = 0
if self.udp_socket == nil return end
var packet = self.udp_socket.read()
while packet != nil
# self.packet = packet
packet_read += 1
var from_addr = self.udp_socket.remote_ip
var from_port = self.udp_socket.remote_port
tasmota.log(string.format("MTR: UDP received from [%s]:%i", from_addr, from_port), 4)
if self.dispatch_cb
self.dispatch_cb(packet, from_addr, from_port)
end
# are we reading new packets?
if packet_read < self.MAX_PACKETS_READ
packet = self.udp_socket.read()
else
packet = nil
end
end
self.resend_packets() # resend any packet
end
#############################################################
def resend_packets()
for packet:self.packets_sent
if tasmota.time_reached(packet.next_try)
tasmota.log("MTR: resending packet id=" + str(packet.msg_id), 3)
packet.send(self.udp_socket) # resend
packet.retries -= 1
if packet.retries <= 0
self.packets_sent.remove(packet.msg_id)
else
packet.next_try = tasmota.millis() + packet.RETRY_MS
end
end
end
end
#############################################################
# just received acknowledgment, remove packet from sender
def packet_ack(id)
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)
end
end
#############################################################
def send_response(raw, addr, port, id)
var packet = matter.UDPPacket_sent(raw, addr, port, id)
packet.send(self.udp_socket) # send
if id
self.packets_sent[id] = packet
end
end
#############################################################
# placeholder, nothing to run for now
def every_second()
end
end
matter.UDPServer = Matter_UDPServer
#-
import matter
var udps = matter.UDPServer()
udps.listen()
-#

View File

@ -0,0 +1,259 @@
#
# Matter_UI.be - WebUI for Matter configuration in Tasmota
#
# 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 Web UI
#
#######################################################################
import matter
#@ solidify:Matter_UI,weak
#################################################################################
# Partition_wizard_UI
#
# WebUI for the partition manager
#################################################################################
class Matter_UI
var device
def init(device)
self.device = device
tasmota.add_driver(self)
end
# ####################################################################################################
# Init web handlers
# ####################################################################################################
# Displays a "Autoconf" button on the configuration page
def web_add_config_button()
import webserver
# webserver.content_send("<p><form id=ac action='matterc' style='display: block;' method='get'><button>Configure Matter</button></form></p>")
webserver.content_send("<p><form id=ac action='matterc' style='display: block;' method='get'><button>")
webserver.content_send(matter._LOGO)
webserver.content_send(" Configure Matter</button></form></p>")
end
#- ---------------------------------------------------------------------- -#
#- Show commissioning information and QR Code
#
# Returns true if Matter is enabled
#- ---------------------------------------------------------------------- -#
def show_enable(p)
import webserver
import string
var matter_enabled = tasmota.get_option(matter.MATTER_OPTION)
webserver.content_send(string.format("<fieldset><legend><b>&nbsp;Matter %s&nbsp;</b></legend><p></p>",
matter_enabled ? "Enabled" : "Disabled"))
webserver.content_send("<p style='width:320px;'>Matter support is experimental.</p>")
webserver.content_send("<form action='/matterc' method='post' onsubmit='return confirm(\"This will cause a restart.\");'>")
webserver.content_send(string.format("<p></p><button name='%s' class='button bgrn'>", matter_enabled ? "disable" : "enable"))
webserver.content_send(matter_enabled ? "Disable" : "Enable")
webserver.content_send(" Matter</button></form></p>")
webserver.content_send("<p></p></fieldset><p></p>")
return matter_enabled
end
#- ---------------------------------------------------------------------- -#
#- Show commissioning information and QR Code
#- ---------------------------------------------------------------------- -#
def show_commissioning_info()
import webserver
import string
webserver.content_send("<fieldset><legend><b>&nbsp;Matter Passcode&nbsp;</b></legend><p></p>")
var pairing_code = self.device.compute_manual_pairing_code()
webserver.content_send(string.format("<p>Manual pairing code:<br><b>%s-%s-%s</b></p><hr>", pairing_code[0..3], pairing_code[4..6], pairing_code[7..]))
var qr_text = self.device.compute_qrcode_content()
webserver.content_send('<div id="qrcode"></div>')
webserver.content_send(string.format('<script type="text/javascript"> new QRCode(document.getElementById("qrcode"), "%s");</script>', qr_text))
webserver.content_send(string.format("<p>%s</p><hr>", qr_text))
webserver.content_send("<form action='/matterc' method='post' >")
webserver.content_send("<p>Passcode:</p>")
webserver.content_send(string.format("<input type='number' min='1' max='99999998' name='passcode' value='%i'>", self.device.passcode))
webserver.content_send("<p>Distinguish id:</p>")
webserver.content_send(string.format("<input type='number' min='0' max='2047' name='discriminator' value='%i'>", self.device.discriminator))
webserver.content_send("<p></p><button name='passcode' class='button bgrn'>Change</button></form></p>")
webserver.content_send("<p></p></fieldset><p></p>")
end
#- ---------------------------------------------------------------------- -#
#- Show commissioning information and QR Code
#- ---------------------------------------------------------------------- -#
def show_session_info(p)
import webserver
import string
webserver.content_send("<fieldset><legend><b>&nbsp;Sessions&nbsp;</b></legend><p></p>")
webserver.content_send("<p>Existing sessions:</p>")
if size(self.device.sessions.sessions) == 0
webserver.content_send("<p><b>None</b></p>")
else
var i = 0
var sz = size(self.device.sessions.sessions)
while i < sz
var s = self.device.sessions.sessions[i]
if s.fabric
webserver.content_send(string.format("<fieldset><legend><b>&nbsp;Session %i&nbsp;</b></legend><p></p>", s.local_session_id))
if i != 0 webserver.content_send("<hr>") end
var fabric_rev = s.fabric.copy().reverse()
var deviceid_rev = s.deviceid.copy().reverse()
webserver.content_send(string.format("Fabric: %s<br>", fabric_rev.tohex()))
webserver.content_send(string.format("Device: %s<br>&nbsp;", deviceid_rev.tohex()))
webserver.content_send("<form action='/matterc' method='post' ")
webserver.content_send("onsubmit='return confirm(\"This will cause a restart.\");'>")
webserver.content_send(string.format("<input name='del_session' type='hidden' value='%d'>", s.local_session_id))
webserver.content_send("<button name='del' class='button bgrn'>Delete Session</button></form></p>")
webserver.content_send("<p></p></fieldset><p></p>")
end
i += 1
end
end
webserver.content_send("<p></p></fieldset><p></p>")
end
#######################################################################
# Serve qrcode.min.js static file
#######################################################################
def page_qrcode_min_js()
import webserver
webserver.content_open(200, "text/javascript")
webserver.content_send(matter._QRCODE_MINJS)
end
#######################################################################
# Display the complete page
#######################################################################
def page_part_mgr()
import webserver
import string
if !webserver.check_privileged_access() return nil end
webserver.content_start("Matter") #- title of the web page -#
webserver.content_send_style() #- send standard Tasmota styles -#
webserver.content_send('<script type="text/javascript" src="qrcode.min.js"></script>')
if self.show_enable()
self.show_commissioning_info()
self.show_session_info()
end
webserver.content_button(webserver.BUTTON_CONFIGURATION)
webserver.content_stop() #- end of web page -#
end
#######################################################################
# Web Controller, called by POST to `/part_wiz`
#######################################################################
def page_part_ctl()
import webserver
if !webserver.check_privileged_access() return nil end
import string
import partition_core
import persist
#- check that the partition is valid -#
var p = partition_core.Partition()
try
#---------------------------------------------------------------------#
# Change Passcode and/or Passcode
#---------------------------------------------------------------------#
if webserver.has_arg("passcode") || webserver.has_arg("discriminator")
if webserver.has_arg("passcode")
self.device.passcode = int(webserver.arg("passcode"))
end
if webserver.has_arg("discriminator")
self.device.discriminator = int(webserver.arg("discriminator"))
end
self.device.save_param()
#- and force restart -#
webserver.redirect("/?rst=")
elif webserver.has_arg("enable")
tasmota.cmd("SetOption" + str(matter.MATTER_OPTION) + " 1")
#- and force restart -#
webserver.redirect("/?rst=")
elif webserver.has_arg("disable")
tasmota.cmd("SetOption" + str(matter.MATTER_OPTION) + " 0")
#- and force restart -#
webserver.redirect("/?rst=")
elif webserver.has_arg("del_session")
var session = self.device.sessions.get_session_by_local_session_id(int(webserver.arg("del_session")))
if session != nil
self.device.sessions.remove_session(session)
self.device.sessions.save()
end
#- and force restart -#
webserver.redirect("/?rst=")
end
except .. as e, m
tasmota.log(string.format("BRY: Exception> '%s' - %s", e, m), 2)
#- display error page -#
webserver.content_start("Parameter error") #- title of the web page -#
webserver.content_send_style() #- send standard Tasmota styles -#
webserver.content_send(string.format("<p style='width:340px;'><b>Exception:</b><br>'%s'<br>%s</p>", e, m))
webserver.content_button(webserver.BUTTON_MANAGEMENT) #- button back to management page -#
webserver.content_stop() #- end of web page -#
end
end
#- ---------------------------------------------------------------------- -#
# respond to web_add_handler() event to register web listeners
#- ---------------------------------------------------------------------- -#
#- this is called at Tasmota start-up, as soon as Wifi/Eth is up and web server running -#
def web_add_handler()
import webserver
#- we need to register a closure, not just a function, that captures the current instance -#
webserver.on("/matterc", / -> self.page_part_mgr(), webserver.HTTP_GET)
webserver.on("/matterc", / -> self.page_part_ctl(), webserver.HTTP_POST)
webserver.on("/qrcode.min.js", / -> self.page_qrcode_min_js(), webserver.HTTP_GET)
end
end
matter.UI = Matter_UI

View File

@ -0,0 +1,64 @@
#
# Matter_inspect.be - implements a generic function to inspect an instance (for debugging only)
#
# 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.sort,weak
def sort(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
return l
end
matter.sort = sort
#@ solidify:matter.inspect,weak
# debug function
def inspect(p)
try
import string
import introspect
var keys = []
for k : introspect.members(p)
var v = introspect.get(p, k)
if type(v) != 'function' keys.push(k) end
end
keys = matter.sort(keys)
var r = []
for k : keys
var v = introspect.get(p, k)
# if type(v) == 'string' v = string.escape(v, true) end
r.push(string.format("'%s': %s", str(k), str(v)))
end
return "{" + r.concat(", ") + "}"
except .. as e, m
return "Exception:" + str(e) + "|" + str(m)
end
end
matter.inspect = inspect

View File

@ -0,0 +1,4 @@
# placeholder for `import matter` not to fail when running solidification
var m = module("matter")
return m

View File

@ -0,0 +1,154 @@
/* Solidification of Matter_Base38.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_Base38;
/********************************************************************
** Solidified function: encode
********************************************************************/
be_local_closure(Matter_Base38_encode, /* name */
be_nested_proto(
10, /* nstack */
1, /* argc */
4, /* varg */
0, /* has upvals */
NULL, /* no upvals */
1, /* has sup protos */
( &(const struct bproto*[ 1]) {
be_nested_proto(
7, /* nstack */
2, /* argc */
0, /* 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(string),
/* K1 */ be_nested_str_weak(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_X2D_X2E),
/* K2 */ be_const_int(0),
/* K3 */ be_nested_str_weak(),
/* K4 */ be_const_int(1),
}),
be_str_weak(b38_enc),
&be_const_str_solidified,
( &(const binstruction[15]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0x580C0001, // 0001 LDCONST R3 K1
0x58100002, // 0002 LDCONST R4 K2
0x58140003, // 0003 LDCONST R5 K3
0x14180801, // 0004 LT R6 R4 R1
0x781A0007, // 0005 JMPF R6 #000E
0x541A0025, // 0006 LDINT R6 38
0x10180006, // 0007 MOD R6 R0 R6
0x94180606, // 0008 GETIDX R6 R3 R6
0x00140A06, // 0009 ADD R5 R5 R6
0x541A0025, // 000A LDINT R6 38
0x0C000006, // 000B DIV R0 R0 R6
0x00100904, // 000C ADD R4 R4 K4
0x7001FFF5, // 000D JMP #0004
0x80040A00, // 000E RET 1 R5
})
),
}),
1, /* has constants */
( &(const bvalue[ 6]) { /* constants */
/* K0 */ be_const_class(be_class_Matter_Base38),
/* K1 */ be_const_int(0),
/* K2 */ be_nested_str_weak(),
/* K3 */ be_const_int(2),
/* K4 */ be_const_int(1),
/* K5 */ be_const_int(3),
}),
be_str_weak(encode),
&be_const_str_solidified,
( &(const binstruction[58]) { /* code */
0x58040000, // 0000 LDCONST R1 K0
0x84080000, // 0001 CLOSURE R2 P0
0x580C0001, // 0002 LDCONST R3 K1
0x6010000C, // 0003 GETGBL R4 G12
0x5C140000, // 0004 MOVE R5 R0
0x7C100200, // 0005 CALL R4 1
0x58140002, // 0006 LDCONST R5 K2
0x14180604, // 0007 LT R6 R3 R4
0x781A002F, // 0008 JMPF R6 #0039
0x4C180000, // 0009 LDNIL R6
0x001C0703, // 000A ADD R7 R3 K3
0x141C0E04, // 000B LT R7 R7 R4
0x781E0012, // 000C JMPF R7 #0020
0x941C0003, // 000D GETIDX R7 R0 R3
0x00200704, // 000E ADD R8 R3 K4
0x94200008, // 000F GETIDX R8 R0 R8
0x54260007, // 0010 LDINT R9 8
0x38201009, // 0011 SHL R8 R8 R9
0x301C0E08, // 0012 OR R7 R7 R8
0x00200703, // 0013 ADD R8 R3 K3
0x94200008, // 0014 GETIDX R8 R0 R8
0x5426000F, // 0015 LDINT R9 16
0x38201009, // 0016 SHL R8 R8 R9
0x301C0E08, // 0017 OR R7 R7 R8
0x5C180E00, // 0018 MOVE R6 R7
0x5C1C0400, // 0019 MOVE R7 R2
0x5C200C00, // 001A MOVE R8 R6
0x54260004, // 001B LDINT R9 5
0x7C1C0400, // 001C CALL R7 2
0x00140A07, // 001D ADD R5 R5 R7
0x000C0705, // 001E ADD R3 R3 K5
0x70020017, // 001F JMP #0038
0x001C0704, // 0020 ADD R7 R3 K4
0x141C0E04, // 0021 LT R7 R7 R4
0x781E000D, // 0022 JMPF R7 #0031
0x941C0003, // 0023 GETIDX R7 R0 R3
0x00200704, // 0024 ADD R8 R3 K4
0x94200008, // 0025 GETIDX R8 R0 R8
0x54260007, // 0026 LDINT R9 8
0x38201009, // 0027 SHL R8 R8 R9
0x301C0E08, // 0028 OR R7 R7 R8
0x5C180E00, // 0029 MOVE R6 R7
0x5C1C0400, // 002A MOVE R7 R2
0x5C200C00, // 002B MOVE R8 R6
0x54260003, // 002C LDINT R9 4
0x7C1C0400, // 002D CALL R7 2
0x00140A07, // 002E ADD R5 R5 R7
0x000C0703, // 002F ADD R3 R3 K3
0x70020006, // 0030 JMP #0038
0x94180003, // 0031 GETIDX R6 R0 R3
0x5C1C0400, // 0032 MOVE R7 R2
0x5C200C00, // 0033 MOVE R8 R6
0x58240003, // 0034 LDCONST R9 K3
0x7C1C0400, // 0035 CALL R7 2
0x00140A07, // 0036 ADD R5 R5 R7
0x000C0704, // 0037 ADD R3 R3 K4
0x7001FFCD, // 0038 JMP #0007
0x80040A00, // 0039 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Base38
********************************************************************/
be_local_class(Matter_Base38,
0,
NULL,
be_nested_map(1,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(encode, -1), be_const_static_closure(Matter_Base38_encode_closure) },
})),
be_str_weak(Matter_Base38)
);
/*******************************************************************/
void be_load_Matter_Base38_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Base38);
be_setglobal(vm, "Matter_Base38");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,970 @@
/* Solidification of Matter_Commissioning_Data.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_PBKDFParamRequest;
/********************************************************************
** Solidified function: parse
********************************************************************/
be_local_closure(Matter_PBKDFParamRequest_parse, /* 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[16]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(parse),
/* K4 */ be_nested_str_weak(initiatorRandom),
/* K5 */ be_nested_str_weak(getsubval),
/* K6 */ be_const_int(1),
/* K7 */ be_nested_str_weak(initiator_session_id),
/* K8 */ be_const_int(2),
/* K9 */ be_nested_str_weak(passcodeId),
/* K10 */ be_const_int(3),
/* K11 */ be_nested_str_weak(hasPBKDFParameters),
/* K12 */ be_nested_str_weak(findsub),
/* K13 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
/* K14 */ be_nested_str_weak(findsubval),
/* K15 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL),
}),
be_str_weak(parse),
&be_const_str_solidified,
( &(const binstruction[41]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
0x58080000, // 0003 LDCONST R2 K0
0xB80E0200, // 0004 GETNGBL R3 K1
0x880C0702, // 0005 GETMBR R3 R3 K2
0x8C0C0703, // 0006 GETMET R3 R3 K3
0x5C140200, // 0007 MOVE R5 R1
0x5C180400, // 0008 MOVE R6 R2
0x7C0C0600, // 0009 CALL R3 3
0x8C100705, // 000A GETMET R4 R3 K5
0x58180006, // 000B LDCONST R6 K6
0x7C100400, // 000C CALL R4 2
0x90020804, // 000D SETMBR R0 K4 R4
0x8C100705, // 000E GETMET R4 R3 K5
0x58180008, // 000F LDCONST R6 K8
0x7C100400, // 0010 CALL R4 2
0x90020E04, // 0011 SETMBR R0 K7 R4
0x8C100705, // 0012 GETMET R4 R3 K5
0x5818000A, // 0013 LDCONST R6 K10
0x7C100400, // 0014 CALL R4 2
0x90021204, // 0015 SETMBR R0 K9 R4
0x8C100705, // 0016 GETMET R4 R3 K5
0x541A0003, // 0017 LDINT R6 4
0x7C100400, // 0018 CALL R4 2
0x90021604, // 0019 SETMBR R0 K11 R4
0x8C10070C, // 001A GETMET R4 R3 K12
0x541A0004, // 001B LDINT R6 5
0x7C100400, // 001C CALL R4 2
0x4C140000, // 001D LDNIL R5
0x20140805, // 001E NE R5 R4 R5
0x78160007, // 001F JMPF R5 #0028
0x8C14090E, // 0020 GETMET R5 R4 K14
0x581C0006, // 0021 LDCONST R7 K6
0x7C140400, // 0022 CALL R5 2
0x90021A05, // 0023 SETMBR R0 K13 R5
0x8C14090E, // 0024 GETMET R5 R4 K14
0x581C0008, // 0025 LDCONST R7 K8
0x7C140400, // 0026 CALL R5 2
0x90021E05, // 0027 SETMBR R0 K15 R5
0x80040000, // 0028 RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_PBKDFParamRequest
********************************************************************/
be_local_class(Matter_PBKDFParamRequest,
6,
NULL,
be_nested_map(7,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(initiatorRandom, 6), be_const_var(0) },
{ be_const_key_weak(passcodeId, -1), be_const_var(2) },
{ be_const_key_weak(hasPBKDFParameters, -1), be_const_var(3) },
{ be_const_key_weak(parse, -1), be_const_closure(Matter_PBKDFParamRequest_parse_closure) },
{ be_const_key_weak(initiator_session_id, 0), be_const_var(1) },
{ be_const_key_weak(SLEEPY_IDLE_INTERVAL, 3), be_const_var(4) },
{ be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(5) },
})),
be_str_weak(Matter_PBKDFParamRequest)
);
/*******************************************************************/
void be_load_Matter_PBKDFParamRequest_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_PBKDFParamRequest);
be_setglobal(vm, "Matter_PBKDFParamRequest");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_PBKDFParamResponse;
/********************************************************************
** Solidified function: encode
********************************************************************/
be_local_closure(Matter_PBKDFParamResponse_encode, /* name */
be_nested_proto(
10, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[19]) { /* constants */
/* K0 */ be_nested_str_weak(matter),
/* K1 */ be_nested_str_weak(TLV),
/* K2 */ be_nested_str_weak(Matter_TLV_struct),
/* K3 */ be_nested_str_weak(add_TLV),
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(B1),
/* K6 */ be_nested_str_weak(initiatorRandom),
/* K7 */ be_const_int(2),
/* K8 */ be_nested_str_weak(responderRandom),
/* K9 */ be_const_int(3),
/* K10 */ be_nested_str_weak(U2),
/* K11 */ be_nested_str_weak(responderSessionId),
/* K12 */ be_nested_str_weak(add_struct),
/* K13 */ be_nested_str_weak(U4),
/* K14 */ be_nested_str_weak(pbkdf_parameters_iterations),
/* K15 */ be_nested_str_weak(pbkdf_parameters_salt),
/* K16 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
/* K17 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL),
/* K18 */ be_nested_str_weak(encode),
}),
be_str_weak(encode),
&be_const_str_solidified,
( &(const binstruction[70]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x88080501, // 0001 GETMBR R2 R2 K1
0x8C080502, // 0002 GETMET R2 R2 K2
0x7C080200, // 0003 CALL R2 1
0x8C0C0503, // 0004 GETMET R3 R2 K3
0x58140004, // 0005 LDCONST R5 K4
0xB81A0000, // 0006 GETNGBL R6 K0
0x88180D01, // 0007 GETMBR R6 R6 K1
0x88180D05, // 0008 GETMBR R6 R6 K5
0x881C0106, // 0009 GETMBR R7 R0 K6
0x7C0C0800, // 000A CALL R3 4
0x8C0C0503, // 000B GETMET R3 R2 K3
0x58140007, // 000C LDCONST R5 K7
0xB81A0000, // 000D GETNGBL R6 K0
0x88180D01, // 000E GETMBR R6 R6 K1
0x88180D05, // 000F GETMBR R6 R6 K5
0x881C0108, // 0010 GETMBR R7 R0 K8
0x7C0C0800, // 0011 CALL R3 4
0x8C0C0503, // 0012 GETMET R3 R2 K3
0x58140009, // 0013 LDCONST R5 K9
0xB81A0000, // 0014 GETNGBL R6 K0
0x88180D01, // 0015 GETMBR R6 R6 K1
0x88180D0A, // 0016 GETMBR R6 R6 K10
0x881C010B, // 0017 GETMBR R7 R0 K11
0x7C0C0800, // 0018 CALL R3 4
0x8C0C050C, // 0019 GETMET R3 R2 K12
0x54160003, // 001A LDINT R5 4
0x7C0C0400, // 001B CALL R3 2
0x8C100703, // 001C GETMET R4 R3 K3
0x58180004, // 001D LDCONST R6 K4
0xB81E0000, // 001E GETNGBL R7 K0
0x881C0F01, // 001F GETMBR R7 R7 K1
0x881C0F0D, // 0020 GETMBR R7 R7 K13
0x8820010E, // 0021 GETMBR R8 R0 K14
0x7C100800, // 0022 CALL R4 4
0x8C100703, // 0023 GETMET R4 R3 K3
0x58180007, // 0024 LDCONST R6 K7
0xB81E0000, // 0025 GETNGBL R7 K0
0x881C0F01, // 0026 GETMBR R7 R7 K1
0x881C0F05, // 0027 GETMBR R7 R7 K5
0x8820010F, // 0028 GETMBR R8 R0 K15
0x7C100800, // 0029 CALL R4 4
0x88100110, // 002A GETMBR R4 R0 K16
0x4C140000, // 002B LDNIL R5
0x20100805, // 002C NE R4 R4 R5
0x74120003, // 002D JMPT R4 #0032
0x88100111, // 002E GETMBR R4 R0 K17
0x4C140000, // 002F LDNIL R5
0x20100805, // 0030 NE R4 R4 R5
0x78120010, // 0031 JMPF R4 #0043
0x8C10050C, // 0032 GETMET R4 R2 K12
0x541A0004, // 0033 LDINT R6 5
0x7C100400, // 0034 CALL R4 2
0x8C140903, // 0035 GETMET R5 R4 K3
0x581C0004, // 0036 LDCONST R7 K4
0xB8220000, // 0037 GETNGBL R8 K0
0x88201101, // 0038 GETMBR R8 R8 K1
0x8820110D, // 0039 GETMBR R8 R8 K13
0x88240110, // 003A GETMBR R9 R0 K16
0x7C140800, // 003B CALL R5 4
0x8C140903, // 003C GETMET R5 R4 K3
0x581C0007, // 003D LDCONST R7 K7
0xB8220000, // 003E GETNGBL R8 K0
0x88201101, // 003F GETMBR R8 R8 K1
0x8820110D, // 0040 GETMBR R8 R8 K13
0x88240111, // 0041 GETMBR R9 R0 K17
0x7C140800, // 0042 CALL R5 4
0x8C100512, // 0043 GETMET R4 R2 K18
0x7C100200, // 0044 CALL R4 1
0x80040800, // 0045 RET 1 R4
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_PBKDFParamResponse
********************************************************************/
be_local_class(Matter_PBKDFParamResponse,
7,
NULL,
be_nested_map(8,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(pbkdf_parameters_salt, -1), be_const_var(4) },
{ be_const_key_weak(SLEEPY_IDLE_INTERVAL, -1), be_const_var(5) },
{ be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 1), be_const_var(6) },
{ be_const_key_weak(responderRandom, -1), be_const_var(1) },
{ be_const_key_weak(pbkdf_parameters_iterations, -1), be_const_var(3) },
{ be_const_key_weak(initiatorRandom, -1), be_const_var(0) },
{ be_const_key_weak(responderSessionId, 3), be_const_var(2) },
{ be_const_key_weak(encode, -1), be_const_closure(Matter_PBKDFParamResponse_encode_closure) },
})),
be_str_weak(Matter_PBKDFParamResponse)
);
/*******************************************************************/
void be_load_Matter_PBKDFParamResponse_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_PBKDFParamResponse);
be_setglobal(vm, "Matter_PBKDFParamResponse");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Pake1;
/********************************************************************
** Solidified function: parse
********************************************************************/
be_local_closure(Matter_Pake1_parse, /* 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[11]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(parse),
/* 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),
}),
be_str_weak(parse),
&be_const_str_solidified,
( &(const binstruction[23]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
0x58080000, // 0003 LDCONST R2 K0
0xB80E0200, // 0004 GETNGBL R3 K1
0x880C0702, // 0005 GETMBR R3 R3 K2
0x8C0C0703, // 0006 GETMET R3 R3 K3
0x5C140200, // 0007 MOVE R5 R1
0x5C180400, // 0008 MOVE R6 R2
0x7C0C0600, // 0009 CALL R3 3
0xB8120800, // 000A GETNGBL R4 K4
0x8C100905, // 000B GETMET R4 R4 K5
0x60180008, // 000C GETGBL R6 G8
0x5C1C0600, // 000D MOVE R7 R3
0x7C180200, // 000E CALL R6 1
0x001A0C06, // 000F ADD R6 K6 R6
0x581C0007, // 0010 LDCONST R7 K7
0x7C100600, // 0011 CALL R4 3
0x8C100709, // 0012 GETMET R4 R3 K9
0x5818000A, // 0013 LDCONST R6 K10
0x7C100400, // 0014 CALL R4 2
0x90021004, // 0015 SETMBR R0 K8 R4
0x80040000, // 0016 RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Pake1
********************************************************************/
be_local_class(Matter_Pake1,
1,
NULL,
be_nested_map(2,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(pA, 1), be_const_var(0) },
{ be_const_key_weak(parse, -1), be_const_closure(Matter_Pake1_parse_closure) },
})),
be_str_weak(Matter_Pake1)
);
/*******************************************************************/
void be_load_Matter_Pake1_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Pake1);
be_setglobal(vm, "Matter_Pake1");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Pake2;
/********************************************************************
** Solidified function: encode
********************************************************************/
be_local_closure(Matter_Pake2_encode, /* name */
be_nested_proto(
8, /* nstack */
2, /* 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(matter),
/* K1 */ be_nested_str_weak(TLV),
/* K2 */ be_nested_str_weak(Matter_TLV_struct),
/* K3 */ be_nested_str_weak(add_TLV),
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(B1),
/* K6 */ be_nested_str_weak(pB),
/* K7 */ be_const_int(2),
/* K8 */ be_nested_str_weak(cB),
/* K9 */ be_nested_str_weak(encode),
}),
be_str_weak(encode),
&be_const_str_solidified,
( &(const binstruction[21]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x88080501, // 0001 GETMBR R2 R2 K1
0x8C080502, // 0002 GETMET R2 R2 K2
0x7C080200, // 0003 CALL R2 1
0x8C0C0503, // 0004 GETMET R3 R2 K3
0x58140004, // 0005 LDCONST R5 K4
0xB81A0000, // 0006 GETNGBL R6 K0
0x88180D01, // 0007 GETMBR R6 R6 K1
0x88180D05, // 0008 GETMBR R6 R6 K5
0x881C0106, // 0009 GETMBR R7 R0 K6
0x7C0C0800, // 000A CALL R3 4
0x8C0C0503, // 000B GETMET R3 R2 K3
0x58140007, // 000C LDCONST R5 K7
0xB81A0000, // 000D GETNGBL R6 K0
0x88180D01, // 000E GETMBR R6 R6 K1
0x88180D05, // 000F GETMBR R6 R6 K5
0x881C0108, // 0010 GETMBR R7 R0 K8
0x7C0C0800, // 0011 CALL R3 4
0x8C0C0509, // 0012 GETMET R3 R2 K9
0x7C0C0200, // 0013 CALL R3 1
0x80040600, // 0014 RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Pake2
********************************************************************/
be_local_class(Matter_Pake2,
2,
NULL,
be_nested_map(3,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(encode, -1), be_const_closure(Matter_Pake2_encode_closure) },
{ be_const_key_weak(cB, -1), be_const_var(1) },
{ be_const_key_weak(pB, 0), be_const_var(0) },
})),
be_str_weak(Matter_Pake2)
);
/*******************************************************************/
void be_load_Matter_Pake2_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Pake2);
be_setglobal(vm, "Matter_Pake2");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Pake3;
/********************************************************************
** Solidified function: parse
********************************************************************/
be_local_closure(Matter_Pake3_parse, /* 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[11]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(parse),
/* 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),
}),
be_str_weak(parse),
&be_const_str_solidified,
( &(const binstruction[23]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
0x58080000, // 0003 LDCONST R2 K0
0xB80E0200, // 0004 GETNGBL R3 K1
0x880C0702, // 0005 GETMBR R3 R3 K2
0x8C0C0703, // 0006 GETMET R3 R3 K3
0x5C140200, // 0007 MOVE R5 R1
0x5C180400, // 0008 MOVE R6 R2
0x7C0C0600, // 0009 CALL R3 3
0xB8120800, // 000A GETNGBL R4 K4
0x8C100905, // 000B GETMET R4 R4 K5
0x60180008, // 000C GETGBL R6 G8
0x5C1C0600, // 000D MOVE R7 R3
0x7C180200, // 000E CALL R6 1
0x001A0C06, // 000F ADD R6 K6 R6
0x581C0007, // 0010 LDCONST R7 K7
0x7C100600, // 0011 CALL R4 3
0x8C100709, // 0012 GETMET R4 R3 K9
0x5818000A, // 0013 LDCONST R6 K10
0x7C100400, // 0014 CALL R4 2
0x90021004, // 0015 SETMBR R0 K8 R4
0x80040000, // 0016 RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Pake3
********************************************************************/
be_local_class(Matter_Pake3,
1,
NULL,
be_nested_map(2,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(parse, -1), be_const_closure(Matter_Pake3_parse_closure) },
{ be_const_key_weak(cA, -1), be_const_var(0) },
})),
be_str_weak(Matter_Pake3)
);
/*******************************************************************/
void be_load_Matter_Pake3_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Pake3);
be_setglobal(vm, "Matter_Pake3");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Sigma1;
/********************************************************************
** Solidified function: parse
********************************************************************/
be_local_closure(Matter_Sigma1_parse, /* name */
be_nested_proto(
9, /* 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_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(parse),
/* K4 */ be_nested_str_weak(Msg1),
/* K5 */ be_const_int(2147483647),
/* 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),
/* K16 */ be_nested_str_weak(initiatorEphPubKey),
/* K17 */ be_nested_str_weak(findsub),
/* K18 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
/* K19 */ be_nested_str_weak(findsubval),
/* K20 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL),
}),
be_str_weak(parse),
&be_const_str_solidified,
( &(const binstruction[58]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
0x58080000, // 0003 LDCONST R2 K0
0xB80E0200, // 0004 GETNGBL R3 K1
0x880C0702, // 0005 GETMBR R3 R3 K2
0x8C0C0703, // 0006 GETMET R3 R3 K3
0x5C140200, // 0007 MOVE R5 R1
0x5C180400, // 0008 MOVE R6 R2
0x7C0C0600, // 0009 CALL R3 3
0x40100505, // 000A CONNECT R4 R2 K5
0x94100204, // 000B GETIDX R4 R1 R4
0x90020804, // 000C SETMBR R0 K4 R4
0xB8120C00, // 000D GETNGBL R4 K6
0x8C100907, // 000E GETMET R4 R4 K7
0x60180008, // 000F GETGBL R6 G8
0x5C1C0600, // 0010 MOVE R7 R3
0x7C180200, // 0011 CALL R6 1
0x001A1006, // 0012 ADD R6 K8 R6
0x581C0009, // 0013 LDCONST R7 K9
0x7C100600, // 0014 CALL R4 3
0x8C10070B, // 0015 GETMET R4 R3 K11
0x5818000C, // 0016 LDCONST R6 K12
0x7C100400, // 0017 CALL R4 2
0x90021404, // 0018 SETMBR R0 K10 R4
0x8C10070B, // 0019 GETMET R4 R3 K11
0x5818000E, // 001A LDCONST R6 K14
0x7C100400, // 001B CALL R4 2
0x90021A04, // 001C SETMBR R0 K13 R4
0x8C10070B, // 001D GETMET R4 R3 K11
0x58180009, // 001E LDCONST R6 K9
0x7C100400, // 001F CALL R4 2
0x90021E04, // 0020 SETMBR R0 K15 R4
0x8C10070B, // 0021 GETMET R4 R3 K11
0x541A0003, // 0022 LDINT R6 4
0x7C100400, // 0023 CALL R4 2
0x90022004, // 0024 SETMBR R0 K16 R4
0x8C100711, // 0025 GETMET R4 R3 K17
0x541A0004, // 0026 LDINT R6 5
0x7C100400, // 0027 CALL R4 2
0x4C140000, // 0028 LDNIL R5
0x20140805, // 0029 NE R5 R4 R5
0x78160007, // 002A JMPF R5 #0033
0x8C140913, // 002B GETMET R5 R4 K19
0x581C000C, // 002C LDCONST R7 K12
0x7C140400, // 002D CALL R5 2
0x90022405, // 002E SETMBR R0 K18 R5
0x8C140913, // 002F GETMET R5 R4 K19
0x581C000E, // 0030 LDCONST R7 K14
0x7C140400, // 0031 CALL R5 2
0x90022805, // 0032 SETMBR R0 K20 R5
0x8C140711, // 0033 GETMET R5 R3 K17
0x541E0005, // 0034 LDINT R7 6
0x7C140400, // 0035 CALL R5 2
0x8C180711, // 0036 GETMET R6 R3 K17
0x54220006, // 0037 LDINT R8 7
0x7C180400, // 0038 CALL R6 2
0x80040000, // 0039 RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Sigma1
********************************************************************/
be_local_class(Matter_Sigma1,
9,
NULL,
be_nested_map(10,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(5) },
{ be_const_key_weak(Msg1, -1), be_const_var(8) },
{ be_const_key_weak(parse, 6), be_const_closure(Matter_Sigma1_parse_closure) },
{ be_const_key_weak(initiatorRandom, -1), be_const_var(0) },
{ be_const_key_weak(SLEEPY_IDLE_INTERVAL, 7), be_const_var(4) },
{ be_const_key_weak(initiatorEphPubKey, -1), be_const_var(3) },
{ be_const_key_weak(initiatorResumeMIC, -1), be_const_var(7) },
{ be_const_key_weak(resumptionID, -1), be_const_var(6) },
{ be_const_key_weak(destinationId, -1), be_const_var(2) },
{ be_const_key_weak(initiator_session_id, 1), be_const_var(1) },
})),
be_str_weak(Matter_Sigma1)
);
/*******************************************************************/
void be_load_Matter_Sigma1_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Sigma1);
be_setglobal(vm, "Matter_Sigma1");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Sigma2;
/********************************************************************
** Solidified function: encode
********************************************************************/
be_local_closure(Matter_Sigma2_encode, /* name */
be_nested_proto(
9, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[18]) { /* constants */
/* K0 */ be_nested_str_weak(matter),
/* K1 */ be_nested_str_weak(TLV),
/* K2 */ be_nested_str_weak(Matter_TLV_struct),
/* K3 */ be_nested_str_weak(add_TLV),
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(B1),
/* K6 */ be_nested_str_weak(responderRandom),
/* K7 */ be_const_int(2),
/* K8 */ be_nested_str_weak(U2),
/* K9 */ be_nested_str_weak(responderSessionId),
/* K10 */ be_const_int(3),
/* K11 */ be_nested_str_weak(responderEphPubKey),
/* K12 */ be_nested_str_weak(encrypted2),
/* K13 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
/* K14 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL),
/* K15 */ be_nested_str_weak(add_struct),
/* K16 */ be_nested_str_weak(U4),
/* K17 */ be_nested_str_weak(encode),
}),
be_str_weak(encode),
&be_const_str_solidified,
( &(const binstruction[60]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x88080501, // 0001 GETMBR R2 R2 K1
0x8C080502, // 0002 GETMET R2 R2 K2
0x7C080200, // 0003 CALL R2 1
0x8C0C0503, // 0004 GETMET R3 R2 K3
0x58140004, // 0005 LDCONST R5 K4
0xB81A0000, // 0006 GETNGBL R6 K0
0x88180D01, // 0007 GETMBR R6 R6 K1
0x88180D05, // 0008 GETMBR R6 R6 K5
0x881C0106, // 0009 GETMBR R7 R0 K6
0x7C0C0800, // 000A CALL R3 4
0x8C0C0503, // 000B GETMET R3 R2 K3
0x58140007, // 000C LDCONST R5 K7
0xB81A0000, // 000D GETNGBL R6 K0
0x88180D01, // 000E GETMBR R6 R6 K1
0x88180D08, // 000F GETMBR R6 R6 K8
0x881C0109, // 0010 GETMBR R7 R0 K9
0x7C0C0800, // 0011 CALL R3 4
0x8C0C0503, // 0012 GETMET R3 R2 K3
0x5814000A, // 0013 LDCONST R5 K10
0xB81A0000, // 0014 GETNGBL R6 K0
0x88180D01, // 0015 GETMBR R6 R6 K1
0x88180D05, // 0016 GETMBR R6 R6 K5
0x881C010B, // 0017 GETMBR R7 R0 K11
0x7C0C0800, // 0018 CALL R3 4
0x8C0C0503, // 0019 GETMET R3 R2 K3
0x54160003, // 001A LDINT R5 4
0xB81A0000, // 001B GETNGBL R6 K0
0x88180D01, // 001C GETMBR R6 R6 K1
0x88180D05, // 001D GETMBR R6 R6 K5
0x881C010C, // 001E GETMBR R7 R0 K12
0x7C0C0800, // 001F CALL R3 4
0x880C010D, // 0020 GETMBR R3 R0 K13
0x4C100000, // 0021 LDNIL R4
0x200C0604, // 0022 NE R3 R3 R4
0x740E0003, // 0023 JMPT R3 #0028
0x880C010E, // 0024 GETMBR R3 R0 K14
0x4C100000, // 0025 LDNIL R4
0x200C0604, // 0026 NE R3 R3 R4
0x780E0010, // 0027 JMPF R3 #0039
0x8C0C050F, // 0028 GETMET R3 R2 K15
0x54160004, // 0029 LDINT R5 5
0x7C0C0400, // 002A CALL R3 2
0x8C100703, // 002B GETMET R4 R3 K3
0x58180004, // 002C LDCONST R6 K4
0xB81E0000, // 002D GETNGBL R7 K0
0x881C0F01, // 002E GETMBR R7 R7 K1
0x881C0F10, // 002F GETMBR R7 R7 K16
0x8820010D, // 0030 GETMBR R8 R0 K13
0x7C100800, // 0031 CALL R4 4
0x8C100703, // 0032 GETMET R4 R3 K3
0x58180007, // 0033 LDCONST R6 K7
0xB81E0000, // 0034 GETNGBL R7 K0
0x881C0F01, // 0035 GETMBR R7 R7 K1
0x881C0F10, // 0036 GETMBR R7 R7 K16
0x8820010E, // 0037 GETMBR R8 R0 K14
0x7C100800, // 0038 CALL R4 4
0x8C0C0511, // 0039 GETMET R3 R2 K17
0x7C0C0200, // 003A CALL R3 1
0x80040600, // 003B RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Sigma2
********************************************************************/
be_local_class(Matter_Sigma2,
6,
NULL,
be_nested_map(7,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(encrypted2, -1), be_const_var(3) },
{ be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2_encode_closure) },
{ be_const_key_weak(responderSessionId, -1), be_const_var(1) },
{ be_const_key_weak(SLEEPY_IDLE_INTERVAL, 6), be_const_var(4) },
{ be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 0), be_const_var(5) },
{ be_const_key_weak(responderRandom, 3), be_const_var(0) },
{ be_const_key_weak(responderEphPubKey, -1), be_const_var(2) },
})),
be_str_weak(Matter_Sigma2)
);
/*******************************************************************/
void be_load_Matter_Sigma2_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Sigma2);
be_setglobal(vm, "Matter_Sigma2");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Sigma2Resume;
/********************************************************************
** Solidified function: encode
********************************************************************/
be_local_closure(Matter_Sigma2Resume_encode, /* name */
be_nested_proto(
9, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[16]) { /* constants */
/* K0 */ be_nested_str_weak(matter),
/* K1 */ be_nested_str_weak(TLV),
/* K2 */ be_nested_str_weak(Matter_TLV_struct),
/* K3 */ be_nested_str_weak(add_TLV),
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(B1),
/* K6 */ be_nested_str_weak(resumptionID),
/* K7 */ be_const_int(2),
/* K8 */ be_nested_str_weak(sigma2ResumeMIC),
/* K9 */ be_const_int(3),
/* K10 */ be_nested_str_weak(responderSessionID),
/* K11 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL),
/* K12 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL),
/* K13 */ be_nested_str_weak(add_struct),
/* K14 */ be_nested_str_weak(U4),
/* K15 */ be_nested_str_weak(encode),
}),
be_str_weak(encode),
&be_const_str_solidified,
( &(const binstruction[53]) { /* code */
0xB80A0000, // 0000 GETNGBL R2 K0
0x88080501, // 0001 GETMBR R2 R2 K1
0x8C080502, // 0002 GETMET R2 R2 K2
0x7C080200, // 0003 CALL R2 1
0x8C0C0503, // 0004 GETMET R3 R2 K3
0x58140004, // 0005 LDCONST R5 K4
0xB81A0000, // 0006 GETNGBL R6 K0
0x88180D01, // 0007 GETMBR R6 R6 K1
0x88180D05, // 0008 GETMBR R6 R6 K5
0x881C0106, // 0009 GETMBR R7 R0 K6
0x7C0C0800, // 000A CALL R3 4
0x8C0C0503, // 000B GETMET R3 R2 K3
0x58140007, // 000C LDCONST R5 K7
0xB81A0000, // 000D GETNGBL R6 K0
0x88180D01, // 000E GETMBR R6 R6 K1
0x88180D05, // 000F GETMBR R6 R6 K5
0x881C0108, // 0010 GETMBR R7 R0 K8
0x7C0C0800, // 0011 CALL R3 4
0x8C0C0503, // 0012 GETMET R3 R2 K3
0x58140009, // 0013 LDCONST R5 K9
0xB81A0000, // 0014 GETNGBL R6 K0
0x88180D01, // 0015 GETMBR R6 R6 K1
0x88180D05, // 0016 GETMBR R6 R6 K5
0x881C010A, // 0017 GETMBR R7 R0 K10
0x7C0C0800, // 0018 CALL R3 4
0x880C010B, // 0019 GETMBR R3 R0 K11
0x4C100000, // 001A LDNIL R4
0x200C0604, // 001B NE R3 R3 R4
0x740E0003, // 001C JMPT R3 #0021
0x880C010C, // 001D GETMBR R3 R0 K12
0x4C100000, // 001E LDNIL R4
0x200C0604, // 001F NE R3 R3 R4
0x780E0010, // 0020 JMPF R3 #0032
0x8C0C050D, // 0021 GETMET R3 R2 K13
0x54160003, // 0022 LDINT R5 4
0x7C0C0400, // 0023 CALL R3 2
0x8C100703, // 0024 GETMET R4 R3 K3
0x58180004, // 0025 LDCONST R6 K4
0xB81E0000, // 0026 GETNGBL R7 K0
0x881C0F01, // 0027 GETMBR R7 R7 K1
0x881C0F0E, // 0028 GETMBR R7 R7 K14
0x8820010B, // 0029 GETMBR R8 R0 K11
0x7C100800, // 002A CALL R4 4
0x8C100703, // 002B GETMET R4 R3 K3
0x58180007, // 002C LDCONST R6 K7
0xB81E0000, // 002D GETNGBL R7 K0
0x881C0F01, // 002E GETMBR R7 R7 K1
0x881C0F0E, // 002F GETMBR R7 R7 K14
0x8820010C, // 0030 GETMBR R8 R0 K12
0x7C100800, // 0031 CALL R4 4
0x8C0C050F, // 0032 GETMET R3 R2 K15
0x7C0C0200, // 0033 CALL R3 1
0x80040600, // 0034 RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Sigma2Resume
********************************************************************/
be_local_class(Matter_Sigma2Resume,
5,
NULL,
be_nested_map(6,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(SLEEPY_IDLE_INTERVAL, 3), be_const_var(3) },
{ be_const_key_weak(resumptionID, -1), be_const_var(0) },
{ be_const_key_weak(sigma2ResumeMIC, -1), be_const_var(1) },
{ be_const_key_weak(responderSessionID, 1), be_const_var(2) },
{ be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(4) },
{ be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2Resume_encode_closure) },
})),
be_str_weak(Matter_Sigma2Resume)
);
/*******************************************************************/
void be_load_Matter_Sigma2Resume_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Sigma2Resume);
be_setglobal(vm, "Matter_Sigma2Resume");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_Sigma3;
/********************************************************************
** Solidified function: parse
********************************************************************/
be_local_closure(Matter_Sigma3_parse, /* 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[13]) { /* constants */
/* K0 */ be_const_int(0),
/* K1 */ be_nested_str_weak(matter),
/* K2 */ be_nested_str_weak(TLV),
/* K3 */ be_nested_str_weak(parse),
/* K4 */ be_nested_str_weak(Msg3),
/* K5 */ be_const_int(2147483647),
/* 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),
}),
be_str_weak(parse),
&be_const_str_solidified,
( &(const binstruction[26]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
0x58080000, // 0003 LDCONST R2 K0
0xB80E0200, // 0004 GETNGBL R3 K1
0x880C0702, // 0005 GETMBR R3 R3 K2
0x8C0C0703, // 0006 GETMET R3 R3 K3
0x5C140200, // 0007 MOVE R5 R1
0x5C180400, // 0008 MOVE R6 R2
0x7C0C0600, // 0009 CALL R3 3
0x40100505, // 000A CONNECT R4 R2 K5
0x94100204, // 000B GETIDX R4 R1 R4
0x90020804, // 000C SETMBR R0 K4 R4
0xB8120C00, // 000D GETNGBL R4 K6
0x8C100907, // 000E GETMET R4 R4 K7
0x60180008, // 000F GETGBL R6 G8
0x5C1C0600, // 0010 MOVE R7 R3
0x7C180200, // 0011 CALL R6 1
0x001A1006, // 0012 ADD R6 K8 R6
0x581C0009, // 0013 LDCONST R7 K9
0x7C100600, // 0014 CALL R4 3
0x8C10070B, // 0015 GETMET R4 R3 K11
0x5818000C, // 0016 LDCONST R6 K12
0x7C100400, // 0017 CALL R4 2
0x90021404, // 0018 SETMBR R0 K10 R4
0x80040000, // 0019 RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Sigma3
********************************************************************/
be_local_class(Matter_Sigma3,
2,
NULL,
be_nested_map(3,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(TBEData3Encrypted, 2), be_const_var(0) },
{ be_const_key_weak(parse, -1), be_const_closure(Matter_Sigma3_parse_closure) },
{ be_const_key_weak(Msg3, -1), be_const_var(1) },
})),
be_str_weak(Matter_Sigma3)
);
/*******************************************************************/
void be_load_Matter_Sigma3_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Sigma3);
be_setglobal(vm, "Matter_Sigma3");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,582 @@
/* Solidification of Matter_MessageHandler.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_MessageHandler;
/********************************************************************
** Solidified function: send_response
********************************************************************/
be_local_closure(Matter_MessageHandler_send_response, /* name */
be_nested_proto(
11, /* nstack */
5, /* 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(device),
/* K1 */ be_nested_str_weak(msg_send),
}),
be_str_weak(send_response),
&be_const_str_solidified,
( &(const binstruction[ 8]) { /* code */
0x88140100, // 0000 GETMBR R5 R0 K0
0x8C140B01, // 0001 GETMET R5 R5 K1
0x5C1C0200, // 0002 MOVE R7 R1
0x5C200400, // 0003 MOVE R8 R2
0x5C240600, // 0004 MOVE R9 R3
0x5C280800, // 0005 MOVE R10 R4
0x7C140A00, // 0006 CALL R5 5
0x80000000, // 0007 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: msg_received
********************************************************************/
be_local_closure(Matter_MessageHandler_msg_received, /* name */
be_nested_proto(
17, /* nstack */
4, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[59]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(log),
/* K3 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20raw_X3D),
/* K4 */ be_nested_str_weak(tohex),
/* K5 */ be_nested_str_weak(matter),
/* K6 */ be_nested_str_weak(Frame),
/* K7 */ be_nested_str_weak(decode_header),
/* K8 */ be_nested_str_weak(local_session_id),
/* K9 */ be_const_int(0),
/* K10 */ be_nested_str_weak(sec_sesstype),
/* K11 */ be_nested_str_weak(device),
/* K12 */ be_nested_str_weak(sessions),
/* K13 */ be_nested_str_weak(find_session_source_id_unsecure),
/* K14 */ be_nested_str_weak(source_node_id),
/* 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),
}),
be_str_weak(msg_received),
&be_const_str_solidified,
( &(const binstruction[289]) { /* code */
0xA4120000, // 0000 IMPORT R4 K0
0xA8020108, // 0001 EXBLK 0 #010B
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
0x7C140600, // 000D CALL R5 3
0x8C180B07, // 000E GETMET R6 R5 K7
0x7C180200, // 000F CALL R6 1
0x5C1C0C00, // 0010 MOVE R7 R6
0x741E0002, // 0011 JMPT R7 #0015
0x501C0000, // 0012 LDBOOL R7 0 0
0xA8040001, // 0013 EXBLK 1 1
0x80040E00, // 0014 RET 1 R7
0x881C0B08, // 0015 GETMBR R7 R5 K8
0x1C1C0F09, // 0016 EQ R7 R7 K9
0x781E0057, // 0017 JMPF R7 #0070
0x881C0B0A, // 0018 GETMBR R7 R5 K10
0x1C1C0F09, // 0019 EQ R7 R7 K9
0x781E0054, // 001A JMPF R7 #0070
0x881C010B, // 001B GETMBR R7 R0 K11
0x881C0F0C, // 001C GETMBR R7 R7 K12
0x8C1C0F0D, // 001D GETMET R7 R7 K13
0x88240B0E, // 001E GETMBR R9 R5 K14
0x542A0059, // 001F LDINT R10 90
0x7C1C0600, // 0020 CALL R7 3
0xB8220200, // 0021 GETNGBL R8 K1
0x8C201102, // 0022 GETMET R8 R8 K2
0x60280008, // 0023 GETGBL R10 G8
0x882C0B0E, // 0024 GETMBR R11 R5 K14
0x7C280200, // 0025 CALL R10 1
0x002A1E0A, // 0026 ADD R10 K15 R10
0x00281510, // 0027 ADD R10 R10 K16
0x602C0008, // 0028 GETGBL R11 G8
0x88300F08, // 0029 GETMBR R12 R7 K8
0x7C2C0200, // 002A CALL R11 1
0x0028140B, // 002B ADD R10 R10 R11
0x582C0011, // 002C LDCONST R11 K17
0x7C200600, // 002D CALL R8 3
0x90162407, // 002E SETMBR R5 K18 R7
0x88200113, // 002F GETMBR R8 R0 K19
0x8C201114, // 0030 GETMET R8 R8 K20
0x88280B15, // 0031 GETMBR R10 R5 K21
0x502C0000, // 0032 LDBOOL R11 0 0
0x7C200600, // 0033 CALL R8 3
0x7422000D, // 0034 JMPT R8 #0043
0xB8220200, // 0035 GETNGBL R8 K1
0x8C201102, // 0036 GETMET R8 R8 K2
0x8C280916, // 0037 GETMET R10 R4 K22
0x58300017, // 0038 LDCONST R12 K23
0x88340B15, // 0039 GETMBR R13 R5 K21
0x88380113, // 003A GETMBR R14 R0 K19
0x8C381D18, // 003B GETMET R14 R14 K24
0x7C380200, // 003C CALL R14 1
0x7C280800, // 003D CALL R10 4
0x582C0011, // 003E LDCONST R11 K17
0x7C200600, // 003F CALL R8 3
0x50200000, // 0040 LDBOOL R8 0 0
0xA8040001, // 0041 EXBLK 1 1
0x80041000, // 0042 RET 1 R8
0x8C200B19, // 0043 GETMET R8 R5 K25
0x7C200200, // 0044 CALL R8 1
0x74220002, // 0045 JMPT R8 #0049
0x50200000, // 0046 LDBOOL R8 0 0
0xA8040001, // 0047 EXBLK 1 1
0x80041000, // 0048 RET 1 R8
0x8820010B, // 0049 GETMBR R8 R0 K11
0x8C20111A, // 004A GETMET R8 R8 K26
0x88280B1B, // 004B GETMBR R10 R5 K27
0x7C200400, // 004C CALL R8 2
0x88200B1C, // 004D GETMBR R8 R5 K28
0x5426000F, // 004E LDINT R9 16
0x20201009, // 004F NE R8 R8 R9
0x78220014, // 0050 JMPF R8 #0066
0xB8220A00, // 0051 GETNGBL R8 K5
0x8C20111D, // 0052 GETMET R8 R8 K29
0x88280B1C, // 0053 GETMBR R10 R5 K28
0x7C200400, // 0054 CALL R8 2
0x5C241000, // 0055 MOVE R9 R8
0x74260004, // 0056 JMPT R9 #005C
0x8C240916, // 0057 GETMET R9 R4 K22
0x582C001E, // 0058 LDCONST R11 K30
0x88300B1C, // 0059 GETMBR R12 R5 K28
0x7C240600, // 005A CALL R9 3
0x5C201200, // 005B MOVE R8 R9
0xB8260200, // 005C GETNGBL R9 K1
0x8C241302, // 005D GETMET R9 R9 K2
0x8C2C0916, // 005E GETMET R11 R4 K22
0x5834001F, // 005F LDCONST R13 K31
0x5C381000, // 0060 MOVE R14 R8
0x5C3C0400, // 0061 MOVE R15 R2
0x5C400600, // 0062 MOVE R16 R3
0x7C2C0A00, // 0063 CALL R11 5
0x58300020, // 0064 LDCONST R12 K32
0x7C240600, // 0065 CALL R9 3
0x88200121, // 0066 GETMBR R8 R0 K33
0x8C201122, // 0067 GETMET R8 R8 K34
0x5C280A00, // 0068 MOVE R10 R5
0x5C2C0400, // 0069 MOVE R11 R2
0x5C300600, // 006A MOVE R12 R3
0x7C200800, // 006B CALL R8 4
0x50200200, // 006C LDBOOL R8 1 0
0xA8040001, // 006D EXBLK 1 1
0x80041000, // 006E RET 1 R8
0x70020095, // 006F JMP #0106
0xB81E0200, // 0070 GETNGBL R7 K1
0x8C1C0F02, // 0071 GETMET R7 R7 K2
0x8C240916, // 0072 GETMET R9 R4 K22
0x582C0023, // 0073 LDCONST R11 K35
0x88300B08, // 0074 GETMBR R12 R5 K8
0x88340B15, // 0075 GETMBR R13 R5 K21
0x7C240800, // 0076 CALL R9 4
0x58280011, // 0077 LDCONST R10 K17
0x7C1C0600, // 0078 CALL R7 3
0x881C010B, // 0079 GETMBR R7 R0 K11
0x881C0F0C, // 007A GETMBR R7 R7 K12
0x8C1C0F24, // 007B GETMET R7 R7 K36
0x88240B08, // 007C GETMBR R9 R5 K8
0x7C1C0400, // 007D CALL R7 2
0x4C200000, // 007E LDNIL R8
0x1C200E08, // 007F EQ R8 R7 R8
0x78220013, // 0080 JMPF R8 #0095
0xB8220200, // 0081 GETNGBL R8 K1
0x8C201102, // 0082 GETMET R8 R8 K2
0x60280008, // 0083 GETGBL R10 G8
0x882C0B08, // 0084 GETMBR R11 R5 K8
0x7C280200, // 0085 CALL R10 1
0x002A4A0A, // 0086 ADD R10 K37 R10
0x582C0011, // 0087 LDCONST R11 K17
0x7C200600, // 0088 CALL R8 3
0xB8220200, // 0089 GETNGBL R8 K1
0x8C201102, // 008A GETMET R8 R8 K2
0xB82A0A00, // 008B GETNGBL R10 K5
0x8C281527, // 008C GETMET R10 R10 K39
0x5C300A00, // 008D MOVE R12 R5
0x7C280400, // 008E CALL R10 2
0x002A4C0A, // 008F ADD R10 K38 R10
0x582C0011, // 0090 LDCONST R11 K17
0x7C200600, // 0091 CALL R8 3
0x50200000, // 0092 LDBOOL R8 0 0
0xA8040001, // 0093 EXBLK 1 1
0x80041000, // 0094 RET 1 R8
0x90162407, // 0095 SETMBR R5 K18 R7
0x88200F13, // 0096 GETMBR R8 R7 K19
0x8C201114, // 0097 GETMET R8 R8 K20
0x88280B15, // 0098 GETMBR R10 R5 K21
0x502C0200, // 0099 LDBOOL R11 1 0
0x7C200600, // 009A CALL R8 3
0x74220011, // 009B JMPT R8 #00AE
0xB8220200, // 009C GETNGBL R8 K1
0x8C201102, // 009D GETMET R8 R8 K2
0x60280008, // 009E GETGBL R10 G8
0x882C0B15, // 009F GETMBR R11 R5 K21
0x7C280200, // 00A0 CALL R10 1
0x002A500A, // 00A1 ADD R10 K40 R10
0x00281529, // 00A2 ADD R10 R10 K41
0x602C0008, // 00A3 GETGBL R11 G8
0x88300F13, // 00A4 GETMBR R12 R7 K19
0x8C301918, // 00A5 GETMET R12 R12 K24
0x7C300200, // 00A6 CALL R12 1
0x7C2C0200, // 00A7 CALL R11 1
0x0028140B, // 00A8 ADD R10 R10 R11
0x582C0011, // 00A9 LDCONST R11 K17
0x7C200600, // 00AA CALL R8 3
0x50200000, // 00AB LDBOOL R8 0 0
0xA8040001, // 00AC EXBLK 1 1
0x80041000, // 00AD RET 1 R8
0x8C200B2A, // 00AE GETMET R8 R5 K42
0x7C200200, // 00AF CALL R8 1
0x5C241000, // 00B0 MOVE R9 R8
0x74260002, // 00B1 JMPT R9 #00B5
0x50240000, // 00B2 LDBOOL R9 0 0
0xA8040001, // 00B3 EXBLK 1 1
0x80041200, // 00B4 RET 1 R9
0x88240B2C, // 00B5 GETMBR R9 R5 K44
0x0424132D, // 00B6 SUB R9 R9 K45
0x40261209, // 00B7 CONNECT R9 K9 R9
0x88280B2B, // 00B8 GETMBR R10 R5 K43
0x94241409, // 00B9 GETIDX R9 R10 R9
0x90165609, // 00BA SETMBR R5 K43 R9
0x88240B2B, // 00BB GETMBR R9 R5 K43
0x40241208, // 00BC CONNECT R9 R9 R8
0xB8260200, // 00BD GETNGBL R9 K1
0x8C241302, // 00BE GETMET R9 R9 K2
0x8C2C0916, // 00BF GETMET R11 R4 K22
0x5834002E, // 00C0 LDCONST R13 K46
0x88380B2C, // 00C1 GETMBR R14 R5 K44
0x883C0B2B, // 00C2 GETMBR R15 R5 K43
0x8C3C1F04, // 00C3 GETMET R15 R15 K4
0x7C3C0200, // 00C4 CALL R15 1
0x7C2C0800, // 00C5 CALL R11 4
0x58300011, // 00C6 LDCONST R12 K17
0x7C240600, // 00C7 CALL R9 3
0x8C240B19, // 00C8 GETMET R9 R5 K25
0x7C240200, // 00C9 CALL R9 1
0xB8260200, // 00CA GETNGBL R9 K1
0x8C241302, // 00CB GETMET R9 R9 K2
0x602C0008, // 00CC GETGBL R11 G8
0x88300B30, // 00CD GETMBR R12 R5 K48
0x7C2C0200, // 00CE CALL R11 1
0x002E5E0B, // 00CF ADD R11 K47 R11
0x002C1731, // 00D0 ADD R11 R11 K49
0x60300008, // 00D1 GETGBL R12 G8
0x88340B1C, // 00D2 GETMBR R13 R5 K28
0x7C300200, // 00D3 CALL R12 1
0x002C160C, // 00D4 ADD R11 R11 R12
0x002C1732, // 00D5 ADD R11 R11 K50
0x60300008, // 00D6 GETGBL R12 G8
0x88340B33, // 00D7 GETMBR R13 R5 K51
0x7C300200, // 00D8 CALL R12 1
0x002C160C, // 00D9 ADD R11 R11 R12
0x58300011, // 00DA LDCONST R12 K17
0x7C240600, // 00DB CALL R9 3
0x8824010B, // 00DC GETMBR R9 R0 K11
0x8C24131A, // 00DD GETMET R9 R9 K26
0x882C0B1B, // 00DE GETMBR R11 R5 K27
0x7C240400, // 00DF CALL R9 2
0x88240B30, // 00E0 GETMBR R9 R5 K48
0x1C281309, // 00E1 EQ R10 R9 K9
0x782A000C, // 00E2 JMPF R10 #00F0
0xB82A0200, // 00E3 GETNGBL R10 K1
0x8C281502, // 00E4 GETMET R10 R10 K2
0xB8320A00, // 00E5 GETNGBL R12 K5
0x8C301927, // 00E6 GETMET R12 R12 K39
0x5C380A00, // 00E7 MOVE R14 R5
0x7C300400, // 00E8 CALL R12 2
0x0032680C, // 00E9 ADD R12 K52 R12
0x58340011, // 00EA LDCONST R13 K17
0x7C280600, // 00EB CALL R10 3
0x50280200, // 00EC LDBOOL R10 1 0
0xA8040001, // 00ED EXBLK 1 1
0x80041400, // 00EE RET 1 R10
0x70020015, // 00EF JMP #0106
0x1C28132D, // 00F0 EQ R10 R9 K45
0x782A0008, // 00F1 JMPF R10 #00FB
0x88280135, // 00F2 GETMBR R10 R0 K53
0x8C281522, // 00F3 GETMET R10 R10 K34
0x5C300A00, // 00F4 MOVE R12 R5
0x5C340400, // 00F5 MOVE R13 R2
0x5C380600, // 00F6 MOVE R14 R3
0x7C280800, // 00F7 CALL R10 4
0xA8040001, // 00F8 EXBLK 1 1
0x80041400, // 00F9 RET 1 R10
0x7002000A, // 00FA JMP #0106
0xB82A0200, // 00FB GETNGBL R10 K1
0x8C281502, // 00FC GETMET R10 R10 K2
0x60300008, // 00FD GETGBL R12 G8
0x5C341200, // 00FE MOVE R13 R9
0x7C300200, // 00FF CALL R12 1
0x00326C0C, // 0100 ADD R12 K54 R12
0x58340011, // 0101 LDCONST R13 K17
0x7C280600, // 0102 CALL R10 3
0x50280000, // 0103 LDBOOL R10 0 0
0xA8040001, // 0104 EXBLK 1 1
0x80041400, // 0105 RET 1 R10
0x501C0200, // 0106 LDBOOL R7 1 0
0xA8040001, // 0107 EXBLK 1 1
0x80040E00, // 0108 RET 1 R7
0xA8040001, // 0109 EXBLK 1 1
0x70020014, // 010A JMP #0120
0xAC140002, // 010B CATCH R5 0 2
0x70020011, // 010C JMP #011F
0xB81E0200, // 010D GETNGBL R7 K1
0x8C1C0F02, // 010E GETMET R7 R7 K2
0x60240008, // 010F GETGBL R9 G8
0x5C280A00, // 0110 MOVE R10 R5
0x7C240200, // 0111 CALL R9 1
0x00266E09, // 0112 ADD R9 K55 R9
0x00241338, // 0113 ADD R9 R9 K56
0x60280008, // 0114 GETGBL R10 G8
0x5C2C0C00, // 0115 MOVE R11 R6
0x7C280200, // 0116 CALL R10 1
0x0024120A, // 0117 ADD R9 R9 R10
0x7C1C0400, // 0118 CALL R7 2
0xA41E7200, // 0119 IMPORT R7 K57
0x8C200F3A, // 011A GETMET R8 R7 K58
0x7C200200, // 011B CALL R8 1
0x50200000, // 011C LDBOOL R8 0 0
0x80041000, // 011D RET 1 R8
0x70020000, // 011E JMP #0120
0xB0080000, // 011F RAISE 2 R0 R0
0x80000000, // 0120 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: add_session
********************************************************************/
be_local_closure(Matter_MessageHandler_add_session, /* name */
be_nested_proto(
15, /* nstack */
7, /* 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(string),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(log),
/* K3 */ be_nested_str_weak(format),
/* K4 */ be_nested_str_weak(MTR_X3A_X20add_session_X20local_session_id_X3D_X25i_X20initiator_session_id_X3D_X25i),
/* K5 */ be_const_int(3),
/* K6 */ be_nested_str_weak(device),
/* K7 */ be_nested_str_weak(sessions),
/* K8 */ be_nested_str_weak(create_session),
/* K9 */ be_nested_str_weak(set_keys),
}),
be_str_weak(add_session),
&be_const_str_solidified,
( &(const binstruction[23]) { /* code */
0xA41E0000, // 0000 IMPORT R7 K0
0xB8220200, // 0001 GETNGBL R8 K1
0x8C201102, // 0002 GETMET R8 R8 K2
0x8C280F03, // 0003 GETMET R10 R7 K3
0x58300004, // 0004 LDCONST R12 K4
0x5C340200, // 0005 MOVE R13 R1
0x5C380400, // 0006 MOVE R14 R2
0x7C280800, // 0007 CALL R10 4
0x582C0005, // 0008 LDCONST R11 K5
0x7C200600, // 0009 CALL R8 3
0x88200106, // 000A GETMBR R8 R0 K6
0x88201107, // 000B GETMBR R8 R8 K7
0x8C201108, // 000C GETMET R8 R8 K8
0x5C280200, // 000D MOVE R10 R1
0x5C2C0400, // 000E MOVE R11 R2
0x7C200600, // 000F CALL R8 3
0x8C241109, // 0010 GETMET R9 R8 K9
0x5C2C0600, // 0011 MOVE R11 R3
0x5C300800, // 0012 MOVE R12 R4
0x5C340A00, // 0013 MOVE R13 R5
0x5C380C00, // 0014 MOVE R14 R6
0x7C240A00, // 0015 CALL R9 5
0x80000000, // 0016 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_MessageHandler_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[ 8]) { /* constants */
/* K0 */ be_nested_str_weak(device),
/* K1 */ be_nested_str_weak(commissioning),
/* K2 */ be_nested_str_weak(matter),
/* K3 */ be_nested_str_weak(Commisioning_Context),
/* K4 */ be_nested_str_weak(im),
/* K5 */ be_nested_str_weak(IM),
/* K6 */ be_nested_str_weak(counter_rcv),
/* K7 */ be_nested_str_weak(Counter),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[16]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0xB80A0400, // 0001 GETNGBL R2 K2
0x8C080503, // 0002 GETMET R2 R2 K3
0x5C100000, // 0003 MOVE R4 R0
0x7C080400, // 0004 CALL R2 2
0x90020202, // 0005 SETMBR R0 K1 R2
0xB80A0400, // 0006 GETNGBL R2 K2
0x8C080505, // 0007 GETMET R2 R2 K5
0x5C100000, // 0008 MOVE R4 R0
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
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: every_second
********************************************************************/
be_local_closure(Matter_MessageHandler_every_second, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str_weak(commissioning),
/* K1 */ be_nested_str_weak(every_second),
/* K2 */ be_nested_str_weak(im),
}),
be_str_weak(every_second),
&be_const_str_solidified,
( &(const binstruction[ 7]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x8C040301, // 0001 GETMET R1 R1 K1
0x7C040200, // 0002 CALL R1 1
0x88040102, // 0003 GETMBR R1 R0 K2
0x8C040301, // 0004 GETMET R1 R1 K1
0x7C040200, // 0005 CALL R1 1
0x80000000, // 0006 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_MessageHandler
********************************************************************/
be_local_class(Matter_MessageHandler,
4,
NULL,
be_nested_map(9,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(every_second, -1), be_const_closure(Matter_MessageHandler_every_second_closure) },
{ be_const_key_weak(msg_received, -1), be_const_closure(Matter_MessageHandler_msg_received_closure) },
{ be_const_key_weak(counter_rcv, -1), be_const_var(3) },
{ be_const_key_weak(commissioning, 0), be_const_var(1) },
{ be_const_key_weak(device, 5), be_const_var(0) },
{ be_const_key_weak(init, 8), be_const_closure(Matter_MessageHandler_init_closure) },
{ be_const_key_weak(send_response, 4), be_const_closure(Matter_MessageHandler_send_response_closure) },
{ be_const_key_weak(add_session, 2), be_const_closure(Matter_MessageHandler_add_session_closure) },
{ be_const_key_weak(im, -1), be_const_var(2) },
})),
be_str_weak(Matter_MessageHandler)
);
/*******************************************************************/
void be_load_Matter_MessageHandler_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_MessageHandler);
be_setglobal(vm, "Matter_MessageHandler");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,90 @@
/* Solidification of Matter_Module.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
/********************************************************************
** Solidified function: setmember
********************************************************************/
be_local_closure(matter_setmember, /* name */
be_nested_proto(
6, /* nstack */
2, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_nested_str_weak(global),
/* K1 */ be_nested_str_weak(contains),
/* K2 */ be_nested_str_weak(_X2Ematter),
}),
be_str_weak(setmember),
&be_const_str_solidified,
( &(const binstruction[11]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0x8C0C0501, // 0001 GETMET R3 R2 K1
0x58140002, // 0002 LDCONST R5 K2
0x7C0C0400, // 0003 CALL R3 2
0x740E0002, // 0004 JMPT R3 #0008
0x600C0013, // 0005 GETGBL R3 G19
0x7C0C0000, // 0006 CALL R3 0
0x900A0403, // 0007 SETMBR R2 K2 R3
0x880C0502, // 0008 GETMBR R3 R2 K2
0x980C0001, // 0009 SETIDX R3 R0 R1
0x80000000, // 000A RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: member
********************************************************************/
be_local_closure(matter_member, /* name */
be_nested_proto(
6, /* nstack */
1, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 4]) { /* constants */
/* K0 */ be_nested_str_weak(global),
/* K1 */ be_nested_str_weak(undefined),
/* K2 */ be_nested_str_weak(contains),
/* K3 */ be_nested_str_weak(_X2Ematter),
}),
be_str_weak(member),
&be_const_str_solidified,
( &(const binstruction[17]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0xA40A0200, // 0001 IMPORT R2 K1
0x8C0C0302, // 0002 GETMET R3 R1 K2
0x58140003, // 0003 LDCONST R5 K3
0x7C0C0400, // 0004 CALL R3 2
0x780E0008, // 0005 JMPF R3 #000F
0x880C0303, // 0006 GETMBR R3 R1 K3
0x8C0C0702, // 0007 GETMET R3 R3 K2
0x5C140000, // 0008 MOVE R5 R0
0x7C0C0400, // 0009 CALL R3 2
0x780E0003, // 000A JMPF R3 #000F
0x880C0303, // 000B GETMBR R3 R1 K3
0x940C0600, // 000C GETIDX R3 R3 R0
0x80040600, // 000D RET 1 R3
0x70020000, // 000E JMP #0010
0x80040400, // 000F RET 1 R2
0x80000000, // 0010 RET 0
})
)
);
/*******************************************************************/
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,272 @@
/* Solidification of Matter_Plugin.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_Plugin;
/********************************************************************
** Solidified function: get_endpoints
********************************************************************/
be_local_closure(Matter_Plugin_get_endpoints, /* name */
be_nested_proto(
2, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_nested_str_weak(endpoints),
}),
be_str_weak(get_endpoints),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x80040200, // 0001 RET 1 R1
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: invoke_request
********************************************************************/
be_local_closure(Matter_Plugin_invoke_request, /* name */
be_nested_proto(
5, /* 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[ 2]) { /* code */
0x4C100000, // 0000 LDNIL R4
0x80040800, // 0001 RET 1 R4
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_Plugin_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(device),
/* K1 */ be_nested_str_weak(endpoints),
}),
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: read_attribute
********************************************************************/
be_local_closure(Matter_Plugin_read_attribute, /* name */
be_nested_proto(
6, /* nstack */
5, /* 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(read_attribute),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: read_event
********************************************************************/
be_local_closure(Matter_Plugin_read_event, /* name */
be_nested_proto(
6, /* nstack */
5, /* 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(read_event),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: subscribe_attribute
********************************************************************/
be_local_closure(Matter_Plugin_subscribe_attribute, /* name */
be_nested_proto(
6, /* nstack */
5, /* 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(subscribe_attribute),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: subscribe_event
********************************************************************/
be_local_closure(Matter_Plugin_subscribe_event, /* name */
be_nested_proto(
6, /* nstack */
5, /* 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(subscribe_event),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: write_attribute
********************************************************************/
be_local_closure(Matter_Plugin_write_attribute, /* name */
be_nested_proto(
6, /* nstack */
5, /* 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(write_attribute),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x80040A00, // 0001 RET 1 R5
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: timed_request
********************************************************************/
be_local_closure(Matter_Plugin_timed_request, /* name */
be_nested_proto(
5, /* 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(timed_request),
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x4C100000, // 0000 LDNIL R4
0x80040800, // 0001 RET 1 R4
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_Plugin
********************************************************************/
be_local_class(Matter_Plugin,
2,
NULL,
be_nested_map(11,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(get_endpoints, -1), be_const_closure(Matter_Plugin_get_endpoints_closure) },
{ be_const_key_weak(endpoints, 7), be_const_var(1) },
{ be_const_key_weak(timed_request, 8), be_const_closure(Matter_Plugin_timed_request_closure) },
{ be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) },
{ be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) },
{ be_const_key_weak(device, -1), be_const_var(0) },
{ be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) },
{ be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_write_attribute_closure) },
{ be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) },
{ be_const_key_weak(init, 2), be_const_closure(Matter_Plugin_init_closure) },
{ be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_invoke_request_closure) },
})),
be_str_weak(Matter_Plugin)
);
/*******************************************************************/
void be_load_Matter_Plugin_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_Plugin);
be_setglobal(vm, "Matter_Plugin");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,118 @@
/* 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(
5, /* nstack */
5, /* 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(read_attribute),
&be_const_str_solidified,
( &(const binstruction[ 1]) { /* code */
0x80000000, // 0000 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[ 3]) { /* constants */
/* K0 */ be_nested_str_weak(init),
/* K1 */ be_nested_str_weak(endpoints),
/* K2 */ be_const_int(1),
}),
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
0x60080012, // 0006 GETGBL R2 G18
0x7C080000, // 0007 CALL R2 0
0x400C0502, // 0008 CONNECT R3 R2 K2
0x90020202, // 0009 SETMBR R0 K1 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(3,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) },
{ be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Relay_init_closure) },
{ 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,626 @@
/* Solidification of Matter_UDPServer.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_UDPPacket_sent;
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_UDPPacket_sent_init, /* name */
be_nested_proto(
7, /* nstack */
5, /* 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(raw),
/* K1 */ be_nested_str_weak(addr),
/* K2 */ be_nested_str_weak(port),
/* K3 */ be_nested_str_weak(msg_id),
/* K4 */ be_nested_str_weak(retries),
/* K5 */ be_nested_str_weak(RETRIES),
/* K6 */ be_nested_str_weak(next_try),
/* K7 */ be_nested_str_weak(tasmota),
/* K8 */ be_nested_str_weak(millis),
/* K9 */ be_nested_str_weak(RETRY_MS),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[13]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x90020202, // 0001 SETMBR R0 K1 R2
0x90020403, // 0002 SETMBR R0 K2 R3
0x90020604, // 0003 SETMBR R0 K3 R4
0x88140105, // 0004 GETMBR R5 R0 K5
0x90020805, // 0005 SETMBR R0 K4 R5
0xB8160E00, // 0006 GETNGBL R5 K7
0x8C140B08, // 0007 GETMET R5 R5 K8
0x7C140200, // 0008 CALL R5 1
0x88180109, // 0009 GETMBR R6 R0 K9
0x00140A06, // 000A ADD R5 R5 R6
0x90020C05, // 000B SETMBR R0 K6 R5
0x80000000, // 000C RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: send
********************************************************************/
be_local_closure(Matter_UDPPacket_sent_send, /* name */
be_nested_proto(
11, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[14]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_nested_str_weak(send),
/* K2 */ be_nested_str_weak(addr),
/* K3 */ be_nested_str_weak(remote_ip),
/* K4 */ be_nested_str_weak(port),
/* K5 */ be_nested_str_weak(remote_port),
/* K6 */ be_nested_str_weak(raw),
/* K7 */ be_nested_str_weak(tasmota),
/* 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),
}),
be_str_weak(send),
&be_const_str_solidified,
( &(const binstruction[35]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0x8C0C0301, // 0001 GETMET R3 R1 K1
0x88140102, // 0002 GETMBR R5 R0 K2
0x78160001, // 0003 JMPF R5 #0006
0x88140102, // 0004 GETMBR R5 R0 K2
0x70020000, // 0005 JMP #0007
0x88140303, // 0006 GETMBR R5 R1 K3
0x88180104, // 0007 GETMBR R6 R0 K4
0x781A0001, // 0008 JMPF R6 #000B
0x88180104, // 0009 GETMBR R6 R0 K4
0x70020000, // 000A JMP #000C
0x88180305, // 000B GETMBR R6 R1 K5
0x881C0106, // 000C GETMBR R7 R0 K6
0x7C0C0800, // 000D CALL R3 4
0x780E0009, // 000E JMPF R3 #0019
0xB8120E00, // 000F GETNGBL R4 K7
0x8C100908, // 0010 GETMET R4 R4 K8
0x8C180509, // 0011 GETMET R6 R2 K9
0x5820000A, // 0012 LDCONST R8 K10
0x88240102, // 0013 GETMBR R9 R0 K2
0x88280104, // 0014 GETMBR R10 R0 K4
0x7C180800, // 0015 CALL R6 4
0x581C000B, // 0016 LDCONST R7 K11
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
0x88240102, // 001D GETMBR R9 R0 K2
0x88280104, // 001E GETMBR R10 R0 K4
0x7C180800, // 001F CALL R6 4
0x581C000D, // 0020 LDCONST R7 K13
0x7C100600, // 0021 CALL R4 3
0x80000000, // 0022 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_UDPPacket_sent
********************************************************************/
be_local_class(Matter_UDPPacket_sent,
6,
NULL,
be_nested_map(10,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(RETRY_MS, 7), be_const_int(500) },
{ be_const_key_weak(raw, 4), be_const_var(0) },
{ be_const_key_weak(next_try, 9), be_const_var(5) },
{ be_const_key_weak(retries, -1), be_const_var(4) },
{ be_const_key_weak(send, 6), be_const_closure(Matter_UDPPacket_sent_send_closure) },
{ be_const_key_weak(init, -1), be_const_closure(Matter_UDPPacket_sent_init_closure) },
{ be_const_key_weak(RETRIES, -1), be_const_int(4) },
{ be_const_key_weak(port, -1), be_const_var(2) },
{ be_const_key_weak(addr, -1), be_const_var(1) },
{ be_const_key_weak(msg_id, -1), be_const_var(3) },
})),
be_str_weak(Matter_UDPPacket_sent)
);
/*******************************************************************/
void be_load_Matter_UDPPacket_sent_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_UDPPacket_sent);
be_setglobal(vm, "Matter_UDPPacket_sent");
be_pop(vm, 1);
}
extern const bclass be_class_Matter_UDPServer;
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_UDPServer_init, /* name */
be_nested_proto(
4, /* nstack */
3, /* 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(address),
/* K1 */ be_nested_str_weak(),
/* K2 */ be_nested_str_weak(port),
/* K3 */ be_nested_str_weak(listening),
/* K4 */ be_nested_str_weak(packets_sent),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[16]) { /* code */
0x78060001, // 0000 JMPF R1 #0003
0x5C0C0200, // 0001 MOVE R3 R1
0x70020000, // 0002 JMP #0004
0x580C0001, // 0003 LDCONST R3 K1
0x90020003, // 0004 SETMBR R0 K0 R3
0x780A0001, // 0005 JMPF R2 #0008
0x5C0C0400, // 0006 MOVE R3 R2
0x70020000, // 0007 JMP #0009
0x540E15A3, // 0008 LDINT R3 5540
0x90020403, // 0009 SETMBR R0 K2 R3
0x500C0000, // 000A LDBOOL R3 0 0
0x90020603, // 000B SETMBR R0 K3 R3
0x600C0013, // 000C GETGBL R3 G19
0x7C0C0000, // 000D CALL R3 0
0x90020803, // 000E SETMBR R0 K4 R3
0x80000000, // 000F RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: every_second
********************************************************************/
be_local_closure(Matter_UDPServer_every_second, /* name */
be_nested_proto(
1, /* nstack */
1, /* 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(every_second),
&be_const_str_solidified,
( &(const binstruction[ 1]) { /* code */
0x80000000, // 0000 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: stop
********************************************************************/
be_local_closure(Matter_UDPServer_stop, /* 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[ 5]) { /* constants */
/* K0 */ be_nested_str_weak(listening),
/* K1 */ be_nested_str_weak(udp_socket),
/* K2 */ be_nested_str_weak(stop),
/* K3 */ be_nested_str_weak(tasmota),
/* K4 */ be_nested_str_weak(remove_driver),
}),
be_str_weak(stop),
&be_const_str_solidified,
( &(const binstruction[12]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x78060008, // 0001 JMPF R1 #000B
0x88040101, // 0002 GETMBR R1 R0 K1
0x8C040302, // 0003 GETMET R1 R1 K2
0x7C040200, // 0004 CALL R1 1
0x50040000, // 0005 LDBOOL R1 0 0
0x90020001, // 0006 SETMBR R0 K0 R1
0xB8060600, // 0007 GETNGBL R1 K3
0x8C040304, // 0008 GETMET R1 R1 K4
0x5C0C0000, // 0009 MOVE R3 R0
0x7C040400, // 000A CALL R1 2
0x80000000, // 000B RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: every_50ms
********************************************************************/
be_local_closure(Matter_UDPServer_every_50ms, /* name */
be_nested_proto(
13, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[14]) { /* constants */
/* K0 */ be_nested_str_weak(string),
/* K1 */ be_const_int(0),
/* K2 */ be_nested_str_weak(udp_socket),
/* K3 */ be_nested_str_weak(read),
/* K4 */ be_const_int(1),
/* K5 */ be_nested_str_weak(remote_ip),
/* K6 */ be_nested_str_weak(remote_port),
/* K7 */ be_nested_str_weak(tasmota),
/* K8 */ be_nested_str_weak(log),
/* K9 */ be_nested_str_weak(format),
/* K10 */ be_nested_str_weak(MTR_X3A_X20UDP_X20received_X20from_X20_X5B_X25s_X5D_X3A_X25i),
/* K11 */ be_nested_str_weak(dispatch_cb),
/* K12 */ be_nested_str_weak(MAX_PACKETS_READ),
/* K13 */ be_nested_str_weak(resend_packets),
}),
be_str_weak(every_50ms),
&be_const_str_solidified,
( &(const binstruction[47]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x58080001, // 0001 LDCONST R2 K1
0x880C0102, // 0002 GETMBR R3 R0 K2
0x4C100000, // 0003 LDNIL R4
0x1C0C0604, // 0004 EQ R3 R3 R4
0x780E0000, // 0005 JMPF R3 #0007
0x80000600, // 0006 RET 0
0x880C0102, // 0007 GETMBR R3 R0 K2
0x8C0C0703, // 0008 GETMET R3 R3 K3
0x7C0C0200, // 0009 CALL R3 1
0x4C100000, // 000A LDNIL R4
0x20100604, // 000B NE R4 R3 R4
0x7812001E, // 000C JMPF R4 #002C
0x00080504, // 000D ADD R2 R2 K4
0x88100102, // 000E GETMBR R4 R0 K2
0x88100905, // 000F GETMBR R4 R4 K5
0x88140102, // 0010 GETMBR R5 R0 K2
0x88140B06, // 0011 GETMBR R5 R5 K6
0xB81A0E00, // 0012 GETNGBL R6 K7
0x8C180D08, // 0013 GETMET R6 R6 K8
0x8C200309, // 0014 GETMET R8 R1 K9
0x5828000A, // 0015 LDCONST R10 K10
0x5C2C0800, // 0016 MOVE R11 R4
0x5C300A00, // 0017 MOVE R12 R5
0x7C200800, // 0018 CALL R8 4
0x54260003, // 0019 LDINT R9 4
0x7C180600, // 001A CALL R6 3
0x8818010B, // 001B GETMBR R6 R0 K11
0x781A0004, // 001C JMPF R6 #0022
0x8C18010B, // 001D GETMET R6 R0 K11
0x5C200600, // 001E MOVE R8 R3
0x5C240800, // 001F MOVE R9 R4
0x5C280A00, // 0020 MOVE R10 R5
0x7C180800, // 0021 CALL R6 4
0x8818010C, // 0022 GETMBR R6 R0 K12
0x14180406, // 0023 LT R6 R2 R6
0x781A0004, // 0024 JMPF R6 #002A
0x88180102, // 0025 GETMBR R6 R0 K2
0x8C180D03, // 0026 GETMET R6 R6 K3
0x7C180200, // 0027 CALL R6 1
0x5C0C0C00, // 0028 MOVE R3 R6
0x70020000, // 0029 JMP #002B
0x4C0C0000, // 002A LDNIL R3
0x7001FFDD, // 002B JMP #000A
0x8C10010D, // 002C GETMET R4 R0 K13
0x7C100200, // 002D CALL R4 1
0x80000000, // 002E RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: resend_packets
********************************************************************/
be_local_closure(Matter_UDPServer_resend_packets, /* name */
be_nested_proto(
7, /* nstack */
1, /* 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(packets_sent),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(time_reached),
/* K3 */ be_nested_str_weak(next_try),
/* K4 */ be_nested_str_weak(log),
/* K5 */ be_nested_str_weak(MTR_X3A_X20resending_X20packet_X20id_X3D),
/* K6 */ be_nested_str_weak(msg_id),
/* K7 */ be_const_int(3),
/* K8 */ be_nested_str_weak(send),
/* K9 */ be_nested_str_weak(udp_socket),
/* 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),
}),
be_str_weak(resend_packets),
&be_const_str_solidified,
( &(const binstruction[44]) { /* code */
0x60040010, // 0000 GETGBL R1 G16
0x88080100, // 0001 GETMBR R2 R0 K0
0x7C040200, // 0002 CALL R1 1
0xA8020023, // 0003 EXBLK 0 #0028
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
0xB80E0200, // 000B GETNGBL R3 K1
0x8C0C0704, // 000C GETMET R3 R3 K4
0x60140008, // 000D GETGBL R5 G8
0x88180506, // 000E GETMBR R6 R2 K6
0x7C140200, // 000F CALL R5 1
0x00160A05, // 0010 ADD R5 K5 R5
0x58180007, // 0011 LDCONST R6 K7
0x7C0C0600, // 0012 CALL R3 3
0x8C0C0508, // 0013 GETMET R3 R2 K8
0x88140109, // 0014 GETMBR R5 R0 K9
0x7C0C0400, // 0015 CALL R3 2
0x880C050A, // 0016 GETMBR R3 R2 K10
0x040C070B, // 0017 SUB R3 R3 K11
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
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: start
********************************************************************/
be_local_closure(Matter_UDPServer_start, /* 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[11]) { /* constants */
/* K0 */ be_nested_str_weak(listening),
/* K1 */ be_nested_str_weak(udp_socket),
/* K2 */ be_nested_str_weak(udp),
/* K3 */ be_nested_str_weak(begin),
/* K4 */ be_nested_str_weak(address),
/* K5 */ be_nested_str_weak(port),
/* K6 */ be_nested_str_weak(network_error),
/* K7 */ be_nested_str_weak(could_X20not_X20open_X20UDP_X20server),
/* K8 */ be_nested_str_weak(dispatch_cb),
/* K9 */ be_nested_str_weak(tasmota),
/* K10 */ be_nested_str_weak(add_driver),
}),
be_str_weak(start),
&be_const_str_solidified,
( &(const binstruction[21]) { /* code */
0x88080100, // 0000 GETMBR R2 R0 K0
0x740A0011, // 0001 JMPT R2 #0014
0xB80A0400, // 0002 GETNGBL R2 K2
0x7C080000, // 0003 CALL R2 0
0x90020202, // 0004 SETMBR R0 K1 R2
0x88080101, // 0005 GETMBR R2 R0 K1
0x8C080503, // 0006 GETMET R2 R2 K3
0x88100104, // 0007 GETMBR R4 R0 K4
0x88140105, // 0008 GETMBR R5 R0 K5
0x7C080600, // 0009 CALL R2 3
0x5C0C0400, // 000A MOVE R3 R2
0x740E0000, // 000B JMPT R3 #000D
0xB0060D07, // 000C RAISE 1 K6 K7
0x500C0200, // 000D LDBOOL R3 1 0
0x90020003, // 000E SETMBR R0 K0 R3
0x90021001, // 000F SETMBR R0 K8 R1
0xB80E1200, // 0010 GETNGBL R3 K9
0x8C0C070A, // 0011 GETMET R3 R3 K10
0x5C140000, // 0012 MOVE R5 R0
0x7C0C0400, // 0013 CALL R3 2
0x80000000, // 0014 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: send_response
********************************************************************/
be_local_closure(Matter_UDPServer_send_response, /* name */
be_nested_proto(
11, /* nstack */
5, /* 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(matter),
/* K1 */ be_nested_str_weak(UDPPacket_sent),
/* K2 */ be_nested_str_weak(send),
/* K3 */ be_nested_str_weak(udp_socket),
/* K4 */ be_nested_str_weak(packets_sent),
}),
be_str_weak(send_response),
&be_const_str_solidified,
( &(const binstruction[14]) { /* code */
0xB8160000, // 0000 GETNGBL R5 K0
0x8C140B01, // 0001 GETMET R5 R5 K1
0x5C1C0200, // 0002 MOVE R7 R1
0x5C200400, // 0003 MOVE R8 R2
0x5C240600, // 0004 MOVE R9 R3
0x5C280800, // 0005 MOVE R10 R4
0x7C140A00, // 0006 CALL R5 5
0x8C180B02, // 0007 GETMET R6 R5 K2
0x88200103, // 0008 GETMBR R8 R0 K3
0x7C180400, // 0009 CALL R6 2
0x78120001, // 000A JMPF R4 #000D
0x88180104, // 000B GETMBR R6 R0 K4
0x98180805, // 000C SETIDX R6 R4 R5
0x80000000, // 000D RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: packet_ack
********************************************************************/
be_local_closure(Matter_UDPServer_packet_ack, /* 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[ 7]) { /* 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,
( &(const binstruction[22]) { /* code */
0x4C080000, // 0000 LDNIL R2
0x1C080202, // 0001 EQ R2 R1 R2
0x780A0000, // 0002 JMPF R2 #0004
0x80000400, // 0003 RET 0
0x88080100, // 0004 GETMBR R2 R0 K0
0x8C080501, // 0005 GETMET R2 R2 K1
0x5C100200, // 0006 MOVE R4 R1
0x7C080400, // 0007 CALL R2 2
0x780A000B, // 0008 JMPF R2 #0015
0x88080100, // 0009 GETMBR R2 R0 K0
0x8C080502, // 000A GETMET R2 R2 K2
0x5C100200, // 000B MOVE R4 R1
0x7C080400, // 000C CALL R2 2
0xB80A0600, // 000D GETNGBL R2 K3
0x8C080504, // 000E GETMET R2 R2 K4
0x60100008, // 000F GETGBL R4 G8
0x5C140200, // 0010 MOVE R5 R1
0x7C100200, // 0011 CALL R4 1
0x00120A04, // 0012 ADD R4 K5 R4
0x58140006, // 0013 LDCONST R5 K6
0x7C080600, // 0014 CALL R2 3
0x80000000, // 0015 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_UDPServer
********************************************************************/
be_local_class(Matter_UDPServer,
6,
NULL,
be_nested_map(15,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(init, 1), be_const_closure(Matter_UDPServer_init_closure) },
{ be_const_key_weak(every_second, -1), be_const_closure(Matter_UDPServer_every_second_closure) },
{ be_const_key_weak(stop, -1), be_const_closure(Matter_UDPServer_stop_closure) },
{ be_const_key_weak(udp_socket, -1), be_const_var(3) },
{ be_const_key_weak(address, -1), be_const_var(0) },
{ be_const_key_weak(dispatch_cb, -1), be_const_var(4) },
{ be_const_key_weak(packet_ack, 7), be_const_closure(Matter_UDPServer_packet_ack_closure) },
{ be_const_key_weak(MAX_PACKETS_READ, 13), be_const_int(4) },
{ be_const_key_weak(every_50ms, 6), be_const_closure(Matter_UDPServer_every_50ms_closure) },
{ be_const_key_weak(listening, -1), be_const_var(2) },
{ be_const_key_weak(port, -1), be_const_var(1) },
{ be_const_key_weak(start, -1), be_const_closure(Matter_UDPServer_start_closure) },
{ be_const_key_weak(send_response, -1), be_const_closure(Matter_UDPServer_send_response_closure) },
{ be_const_key_weak(resend_packets, -1), be_const_closure(Matter_UDPServer_resend_packets_closure) },
{ be_const_key_weak(packets_sent, -1), be_const_var(5) },
})),
be_str_weak(Matter_UDPServer)
);
/*******************************************************************/
void be_load_Matter_UDPServer_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_UDPServer);
be_setglobal(vm, "Matter_UDPServer");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,893 @@
/* Solidification of Matter_UI.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
extern const bclass be_class_Matter_UI;
/********************************************************************
** Solidified function: show_commissioning_info
********************************************************************/
be_local_closure(Matter_UI_show_commissioning_info, /* name */
be_nested_proto(
12, /* nstack */
1, /* 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(webserver),
/* K1 */ be_nested_str_weak(string),
/* K2 */ be_nested_str_weak(content_send),
/* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20Passcode_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
/* K4 */ be_nested_str_weak(device),
/* K5 */ be_nested_str_weak(compute_manual_pairing_code),
/* K6 */ be_nested_str_weak(format),
/* K7 */ be_nested_str_weak(_X3Cp_X3EManual_X20pairing_X20code_X3A_X3Cbr_X3E_X3Cb_X3E_X25s_X2D_X25s_X2D_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E_X3Chr_X3E),
/* K8 */ be_const_int(0),
/* K9 */ be_const_int(3),
/* K10 */ be_const_int(2147483647),
/* K11 */ be_nested_str_weak(compute_qrcode_content),
/* K12 */ be_nested_str_weak(_X3Cdiv_X20id_X3D_X22qrcode_X22_X3E_X3C_X2Fdiv_X3E),
/* K13 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X3E_X20new_X20QRCode_X28document_X2EgetElementById_X28_X22qrcode_X22_X29_X2C_X20_X22_X25s_X22_X29_X3B_X3C_X2Fscript_X3E),
/* K14 */ be_nested_str_weak(_X3Cp_X3E_X25s_X3C_X2Fp_X3E_X3Chr_X3E),
/* K15 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20_X3E),
/* K16 */ be_nested_str_weak(_X3Cp_X3EPasscode_X3A_X3C_X2Fp_X3E),
/* K17 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X271_X27_X20max_X3D_X2799999998_X27_X20name_X3D_X27passcode_X27_X20value_X3D_X27_X25i_X27_X3E),
/* K18 */ be_nested_str_weak(passcode),
/* K19 */ be_nested_str_weak(_X3Cp_X3EDistinguish_X20id_X3A_X3C_X2Fp_X3E),
/* K20 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X270_X27_X20max_X3D_X272047_X27_X20name_X3D_X27discriminator_X27_X20value_X3D_X27_X25i_X27_X3E),
/* K21 */ be_nested_str_weak(discriminator),
/* K22 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27passcode_X27_X20class_X3D_X27button_X20bgrn_X27_X3EChange_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
/* K23 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
}),
be_str_weak(show_commissioning_info),
&be_const_str_solidified,
( &(const binstruction[70]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0xA40A0200, // 0001 IMPORT R2 K1
0x8C0C0302, // 0002 GETMET R3 R1 K2
0x58140003, // 0003 LDCONST R5 K3
0x7C0C0400, // 0004 CALL R3 2
0x880C0104, // 0005 GETMBR R3 R0 K4
0x8C0C0705, // 0006 GETMET R3 R3 K5
0x7C0C0200, // 0007 CALL R3 1
0x8C100302, // 0008 GETMET R4 R1 K2
0x8C180506, // 0009 GETMET R6 R2 K6
0x58200007, // 000A LDCONST R8 K7
0x40261109, // 000B CONNECT R9 K8 K9
0x94240609, // 000C GETIDX R9 R3 R9
0x542A0003, // 000D LDINT R10 4
0x542E0005, // 000E LDINT R11 6
0x4028140B, // 000F CONNECT R10 R10 R11
0x9428060A, // 0010 GETIDX R10 R3 R10
0x542E0006, // 0011 LDINT R11 7
0x402C170A, // 0012 CONNECT R11 R11 K10
0x942C060B, // 0013 GETIDX R11 R3 R11
0x7C180A00, // 0014 CALL R6 5
0x7C100400, // 0015 CALL R4 2
0x88100104, // 0016 GETMBR R4 R0 K4
0x8C10090B, // 0017 GETMET R4 R4 K11
0x7C100200, // 0018 CALL R4 1
0x8C140302, // 0019 GETMET R5 R1 K2
0x581C000C, // 001A LDCONST R7 K12
0x7C140400, // 001B CALL R5 2
0x8C140302, // 001C GETMET R5 R1 K2
0x8C1C0506, // 001D GETMET R7 R2 K6
0x5824000D, // 001E LDCONST R9 K13
0x5C280800, // 001F MOVE R10 R4
0x7C1C0600, // 0020 CALL R7 3
0x7C140400, // 0021 CALL R5 2
0x8C140302, // 0022 GETMET R5 R1 K2
0x8C1C0506, // 0023 GETMET R7 R2 K6
0x5824000E, // 0024 LDCONST R9 K14
0x5C280800, // 0025 MOVE R10 R4
0x7C1C0600, // 0026 CALL R7 3
0x7C140400, // 0027 CALL R5 2
0x8C140302, // 0028 GETMET R5 R1 K2
0x581C000F, // 0029 LDCONST R7 K15
0x7C140400, // 002A CALL R5 2
0x8C140302, // 002B GETMET R5 R1 K2
0x581C0010, // 002C LDCONST R7 K16
0x7C140400, // 002D CALL R5 2
0x8C140302, // 002E GETMET R5 R1 K2
0x8C1C0506, // 002F GETMET R7 R2 K6
0x58240011, // 0030 LDCONST R9 K17
0x88280104, // 0031 GETMBR R10 R0 K4
0x88281512, // 0032 GETMBR R10 R10 K18
0x7C1C0600, // 0033 CALL R7 3
0x7C140400, // 0034 CALL R5 2
0x8C140302, // 0035 GETMET R5 R1 K2
0x581C0013, // 0036 LDCONST R7 K19
0x7C140400, // 0037 CALL R5 2
0x8C140302, // 0038 GETMET R5 R1 K2
0x8C1C0506, // 0039 GETMET R7 R2 K6
0x58240014, // 003A LDCONST R9 K20
0x88280104, // 003B GETMBR R10 R0 K4
0x88281515, // 003C GETMBR R10 R10 K21
0x7C1C0600, // 003D CALL R7 3
0x7C140400, // 003E CALL R5 2
0x8C140302, // 003F GETMET R5 R1 K2
0x581C0016, // 0040 LDCONST R7 K22
0x7C140400, // 0041 CALL R5 2
0x8C140302, // 0042 GETMET R5 R1 K2
0x581C0017, // 0043 LDCONST R7 K23
0x7C140400, // 0044 CALL R5 2
0x80000000, // 0045 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: web_add_handler
********************************************************************/
be_local_closure(Matter_UI_web_add_handler, /* name */
be_nested_proto(
7, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
1, /* has sup protos */
( &(const struct bproto*[ 3]) {
be_nested_proto(
2, /* nstack */
0, /* argc */
0, /* varg */
1, /* has upvals */
( &(const bupvaldesc[ 1]) { /* upvals */
be_local_const_upval(1, 0),
}),
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_nested_str_weak(page_part_mgr),
}),
be_str_weak(_X3Clambda_X3E),
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x68000000, // 0000 GETUPV R0 U0
0x8C000100, // 0001 GETMET R0 R0 K0
0x7C000200, // 0002 CALL R0 1
0x80040000, // 0003 RET 1 R0
})
),
be_nested_proto(
2, /* nstack */
0, /* argc */
0, /* varg */
1, /* has upvals */
( &(const bupvaldesc[ 1]) { /* upvals */
be_local_const_upval(1, 0),
}),
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_nested_str_weak(page_part_ctl),
}),
be_str_weak(_X3Clambda_X3E),
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x68000000, // 0000 GETUPV R0 U0
0x8C000100, // 0001 GETMET R0 R0 K0
0x7C000200, // 0002 CALL R0 1
0x80040000, // 0003 RET 1 R0
})
),
be_nested_proto(
2, /* nstack */
0, /* argc */
0, /* varg */
1, /* has upvals */
( &(const bupvaldesc[ 1]) { /* upvals */
be_local_const_upval(1, 0),
}),
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
/* K0 */ be_nested_str_weak(page_qrcode_min_js),
}),
be_str_weak(_X3Clambda_X3E),
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x68000000, // 0000 GETUPV R0 U0
0x8C000100, // 0001 GETMET R0 R0 K0
0x7C000200, // 0002 CALL R0 1
0x80040000, // 0003 RET 1 R0
})
),
}),
1, /* has constants */
( &(const bvalue[ 6]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(on),
/* K2 */ be_nested_str_weak(_X2Fmatterc),
/* K3 */ be_nested_str_weak(HTTP_GET),
/* K4 */ be_nested_str_weak(HTTP_POST),
/* K5 */ be_nested_str_weak(_X2Fqrcode_X2Emin_X2Ejs),
}),
be_str_weak(web_add_handler),
&be_const_str_solidified,
( &(const binstruction[18]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x8C080301, // 0001 GETMET R2 R1 K1
0x58100002, // 0002 LDCONST R4 K2
0x84140000, // 0003 CLOSURE R5 P0
0x88180303, // 0004 GETMBR R6 R1 K3
0x7C080800, // 0005 CALL R2 4
0x8C080301, // 0006 GETMET R2 R1 K1
0x58100002, // 0007 LDCONST R4 K2
0x84140001, // 0008 CLOSURE R5 P1
0x88180304, // 0009 GETMBR R6 R1 K4
0x7C080800, // 000A CALL R2 4
0x8C080301, // 000B GETMET R2 R1 K1
0x58100005, // 000C LDCONST R4 K5
0x84140002, // 000D CLOSURE R5 P2
0x88180303, // 000E GETMBR R6 R1 K3
0x7C080800, // 000F CALL R2 4
0xA0000000, // 0010 CLOSE R0
0x80000000, // 0011 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: show_session_info
********************************************************************/
be_local_closure(Matter_UI_show_session_info, /* name */
be_nested_proto(
16, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[26]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(string),
/* K2 */ be_nested_str_weak(content_send),
/* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSessions_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
/* K4 */ be_nested_str_weak(_X3Cp_X3EExisting_X20sessions_X3A_X3C_X2Fp_X3E),
/* K5 */ be_nested_str_weak(device),
/* K6 */ be_nested_str_weak(sessions),
/* K7 */ be_const_int(0),
/* K8 */ be_nested_str_weak(_X3Cp_X3E_X3Cb_X3ENone_X3C_X2Fb_X3E_X3C_X2Fp_X3E),
/* K9 */ be_nested_str_weak(fabric),
/* K10 */ be_nested_str_weak(format),
/* K11 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSession_X20_X25i_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
/* K12 */ be_nested_str_weak(local_session_id),
/* K13 */ be_nested_str_weak(_X3Chr_X3E),
/* K14 */ be_nested_str_weak(copy),
/* K15 */ be_nested_str_weak(reverse),
/* K16 */ be_nested_str_weak(deviceid),
/* K17 */ be_nested_str_weak(Fabric_X3A_X20_X25s_X3Cbr_X3E),
/* K18 */ be_nested_str_weak(tohex),
/* K19 */ be_nested_str_weak(Device_X3A_X20_X25s_X3Cbr_X3E_X26nbsp_X3B),
/* K20 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20),
/* K21 */ be_nested_str_weak(onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E),
/* K22 */ be_nested_str_weak(_X3Cinput_X20name_X3D_X27del_session_X27_X20type_X3D_X27hidden_X27_X20value_X3D_X27_X25d_X27_X3E),
/* K23 */ be_nested_str_weak(_X3Cbutton_X20name_X3D_X27del_X27_X20class_X3D_X27button_X20bgrn_X27_X3EDelete_X20Session_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
/* K24 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
/* K25 */ be_const_int(1),
}),
be_str_weak(show_session_info),
&be_const_str_solidified,
( &(const binstruction[92]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0xA40E0200, // 0001 IMPORT R3 K1
0x8C100502, // 0002 GETMET R4 R2 K2
0x58180003, // 0003 LDCONST R6 K3
0x7C100400, // 0004 CALL R4 2
0x8C100502, // 0005 GETMET R4 R2 K2
0x58180004, // 0006 LDCONST R6 K4
0x7C100400, // 0007 CALL R4 2
0x6010000C, // 0008 GETGBL R4 G12
0x88140105, // 0009 GETMBR R5 R0 K5
0x88140B06, // 000A GETMBR R5 R5 K6
0x88140B06, // 000B GETMBR R5 R5 K6
0x7C100200, // 000C CALL R4 1
0x1C100907, // 000D EQ R4 R4 K7
0x78120003, // 000E JMPF R4 #0013
0x8C100502, // 000F GETMET R4 R2 K2
0x58180008, // 0010 LDCONST R6 K8
0x7C100400, // 0011 CALL R4 2
0x70020044, // 0012 JMP #0058
0x58100007, // 0013 LDCONST R4 K7
0x6014000C, // 0014 GETGBL R5 G12
0x88180105, // 0015 GETMBR R6 R0 K5
0x88180D06, // 0016 GETMBR R6 R6 K6
0x88180D06, // 0017 GETMBR R6 R6 K6
0x7C140200, // 0018 CALL R5 1
0x14180805, // 0019 LT R6 R4 R5
0x781A003C, // 001A JMPF R6 #0058
0x88180105, // 001B GETMBR R6 R0 K5
0x88180D06, // 001C GETMBR R6 R6 K6
0x88180D06, // 001D GETMBR R6 R6 K6
0x94180C04, // 001E GETIDX R6 R6 R4
0x881C0D09, // 001F GETMBR R7 R6 K9
0x781E0034, // 0020 JMPF R7 #0056
0x8C1C0502, // 0021 GETMET R7 R2 K2
0x8C24070A, // 0022 GETMET R9 R3 K10
0x582C000B, // 0023 LDCONST R11 K11
0x88300D0C, // 0024 GETMBR R12 R6 K12
0x7C240600, // 0025 CALL R9 3
0x7C1C0400, // 0026 CALL R7 2
0x201C0907, // 0027 NE R7 R4 K7
0x781E0002, // 0028 JMPF R7 #002C
0x8C1C0502, // 0029 GETMET R7 R2 K2
0x5824000D, // 002A LDCONST R9 K13
0x7C1C0400, // 002B CALL R7 2
0x881C0D09, // 002C GETMBR R7 R6 K9
0x8C1C0F0E, // 002D GETMET R7 R7 K14
0x7C1C0200, // 002E CALL R7 1
0x8C1C0F0F, // 002F GETMET R7 R7 K15
0x7C1C0200, // 0030 CALL R7 1
0x88200D10, // 0031 GETMBR R8 R6 K16
0x8C20110E, // 0032 GETMET R8 R8 K14
0x7C200200, // 0033 CALL R8 1
0x8C20110F, // 0034 GETMET R8 R8 K15
0x7C200200, // 0035 CALL R8 1
0x8C240502, // 0036 GETMET R9 R2 K2
0x8C2C070A, // 0037 GETMET R11 R3 K10
0x58340011, // 0038 LDCONST R13 K17
0x8C380F12, // 0039 GETMET R14 R7 K18
0x7C380200, // 003A CALL R14 1
0x7C2C0600, // 003B CALL R11 3
0x7C240400, // 003C CALL R9 2
0x8C240502, // 003D GETMET R9 R2 K2
0x8C2C070A, // 003E GETMET R11 R3 K10
0x58340013, // 003F LDCONST R13 K19
0x8C381112, // 0040 GETMET R14 R8 K18
0x7C380200, // 0041 CALL R14 1
0x7C2C0600, // 0042 CALL R11 3
0x7C240400, // 0043 CALL R9 2
0x8C240502, // 0044 GETMET R9 R2 K2
0x582C0014, // 0045 LDCONST R11 K20
0x7C240400, // 0046 CALL R9 2
0x8C240502, // 0047 GETMET R9 R2 K2
0x582C0015, // 0048 LDCONST R11 K21
0x7C240400, // 0049 CALL R9 2
0x8C240502, // 004A GETMET R9 R2 K2
0x8C2C070A, // 004B GETMET R11 R3 K10
0x58340016, // 004C LDCONST R13 K22
0x88380D0C, // 004D GETMBR R14 R6 K12
0x7C2C0600, // 004E CALL R11 3
0x7C240400, // 004F CALL R9 2
0x8C240502, // 0050 GETMET R9 R2 K2
0x582C0017, // 0051 LDCONST R11 K23
0x7C240400, // 0052 CALL R9 2
0x8C240502, // 0053 GETMET R9 R2 K2
0x582C0018, // 0054 LDCONST R11 K24
0x7C240400, // 0055 CALL R9 2
0x00100919, // 0056 ADD R4 R4 K25
0x7001FFC0, // 0057 JMP #0019
0x8C100502, // 0058 GETMET R4 R2 K2
0x58180018, // 0059 LDCONST R6 K24
0x7C100400, // 005A CALL R4 2
0x80000000, // 005B RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: show_enable
********************************************************************/
be_local_closure(Matter_UI_show_enable, /* name */
be_nested_proto(
11, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[20]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(string),
/* K2 */ be_nested_str_weak(tasmota),
/* K3 */ be_nested_str_weak(get_option),
/* K4 */ be_nested_str_weak(matter),
/* K5 */ be_nested_str_weak(MATTER_OPTION),
/* K6 */ be_nested_str_weak(content_send),
/* K7 */ be_nested_str_weak(format),
/* K8 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20_X25s_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
/* K9 */ be_nested_str_weak(Enabled),
/* K10 */ be_nested_str_weak(Disabled),
/* K11 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A320px_X3B_X27_X3EMatter_X20support_X20is_X20experimental_X2E_X3C_X2Fp_X3E),
/* K12 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E),
/* K13 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27_X25s_X27_X20class_X3D_X27button_X20bgrn_X27_X3E),
/* K14 */ be_nested_str_weak(disable),
/* K15 */ be_nested_str_weak(enable),
/* K16 */ be_nested_str_weak(Disable),
/* K17 */ be_nested_str_weak(Enable),
/* K18 */ be_nested_str_weak(_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
/* K19 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E),
}),
be_str_weak(show_enable),
&be_const_str_solidified,
( &(const binstruction[44]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0xA40E0200, // 0001 IMPORT R3 K1
0xB8120400, // 0002 GETNGBL R4 K2
0x8C100903, // 0003 GETMET R4 R4 K3
0xB81A0800, // 0004 GETNGBL R6 K4
0x88180D05, // 0005 GETMBR R6 R6 K5
0x7C100400, // 0006 CALL R4 2
0x8C140506, // 0007 GETMET R5 R2 K6
0x8C1C0707, // 0008 GETMET R7 R3 K7
0x58240008, // 0009 LDCONST R9 K8
0x78120001, // 000A JMPF R4 #000D
0x58280009, // 000B LDCONST R10 K9
0x70020000, // 000C JMP #000E
0x5828000A, // 000D LDCONST R10 K10
0x7C1C0600, // 000E CALL R7 3
0x7C140400, // 000F CALL R5 2
0x8C140506, // 0010 GETMET R5 R2 K6
0x581C000B, // 0011 LDCONST R7 K11
0x7C140400, // 0012 CALL R5 2
0x8C140506, // 0013 GETMET R5 R2 K6
0x581C000C, // 0014 LDCONST R7 K12
0x7C140400, // 0015 CALL R5 2
0x8C140506, // 0016 GETMET R5 R2 K6
0x8C1C0707, // 0017 GETMET R7 R3 K7
0x5824000D, // 0018 LDCONST R9 K13
0x78120001, // 0019 JMPF R4 #001C
0x5828000E, // 001A LDCONST R10 K14
0x70020000, // 001B JMP #001D
0x5828000F, // 001C LDCONST R10 K15
0x7C1C0600, // 001D CALL R7 3
0x7C140400, // 001E CALL R5 2
0x8C140506, // 001F GETMET R5 R2 K6
0x78120001, // 0020 JMPF R4 #0023
0x581C0010, // 0021 LDCONST R7 K16
0x70020000, // 0022 JMP #0024
0x581C0011, // 0023 LDCONST R7 K17
0x7C140400, // 0024 CALL R5 2
0x8C140506, // 0025 GETMET R5 R2 K6
0x581C0012, // 0026 LDCONST R7 K18
0x7C140400, // 0027 CALL R5 2
0x8C140506, // 0028 GETMET R5 R2 K6
0x581C0013, // 0029 LDCONST R7 K19
0x7C140400, // 002A CALL R5 2
0x80040800, // 002B RET 1 R4
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(Matter_UI_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[ 3]) { /* constants */
/* K0 */ be_nested_str_weak(device),
/* K1 */ be_nested_str_weak(tasmota),
/* K2 */ be_nested_str_weak(add_driver),
}),
be_str_weak(init),
&be_const_str_solidified,
( &(const binstruction[ 6]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0xB80A0200, // 0001 GETNGBL R2 K1
0x8C080502, // 0002 GETMET R2 R2 K2
0x5C100000, // 0003 MOVE R4 R0
0x7C080400, // 0004 CALL R2 2
0x80000000, // 0005 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: page_part_ctl
********************************************************************/
be_local_closure(Matter_UI_page_part_ctl, /* name */
be_nested_proto(
15, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[40]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(check_privileged_access),
/* K2 */ be_nested_str_weak(string),
/* K3 */ be_nested_str_weak(partition_core),
/* K4 */ be_nested_str_weak(persist),
/* K5 */ be_nested_str_weak(Partition),
/* K6 */ be_nested_str_weak(has_arg),
/* K7 */ be_nested_str_weak(passcode),
/* K8 */ be_nested_str_weak(discriminator),
/* K9 */ be_nested_str_weak(device),
/* K10 */ be_nested_str_weak(arg),
/* K11 */ be_nested_str_weak(save_param),
/* K12 */ be_nested_str_weak(redirect),
/* K13 */ be_nested_str_weak(_X2F_X3Frst_X3D),
/* K14 */ be_nested_str_weak(enable),
/* K15 */ be_nested_str_weak(tasmota),
/* K16 */ be_nested_str_weak(cmd),
/* K17 */ be_nested_str_weak(SetOption),
/* K18 */ be_nested_str_weak(matter),
/* K19 */ be_nested_str_weak(MATTER_OPTION),
/* K20 */ be_nested_str_weak(_X201),
/* K21 */ be_nested_str_weak(disable),
/* K22 */ be_nested_str_weak(_X200),
/* K23 */ be_nested_str_weak(del_session),
/* K24 */ be_nested_str_weak(sessions),
/* K25 */ be_nested_str_weak(get_session_by_local_session_id),
/* K26 */ be_nested_str_weak(remove_session),
/* K27 */ be_nested_str_weak(save),
/* K28 */ be_nested_str_weak(log),
/* K29 */ be_nested_str_weak(format),
/* K30 */ be_nested_str_weak(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s),
/* K31 */ be_const_int(2),
/* K32 */ be_nested_str_weak(content_start),
/* K33 */ be_nested_str_weak(Parameter_X20error),
/* K34 */ be_nested_str_weak(content_send_style),
/* K35 */ be_nested_str_weak(content_send),
/* K36 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E),
/* K37 */ be_nested_str_weak(content_button),
/* K38 */ be_nested_str_weak(BUTTON_MANAGEMENT),
/* K39 */ be_nested_str_weak(content_stop),
}),
be_str_weak(page_part_ctl),
&be_const_str_solidified,
( &(const binstruction[144]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x8C080301, // 0001 GETMET R2 R1 K1
0x7C080200, // 0002 CALL R2 1
0x740A0001, // 0003 JMPT R2 #0006
0x4C080000, // 0004 LDNIL R2
0x80040400, // 0005 RET 1 R2
0xA40A0400, // 0006 IMPORT R2 K2
0xA40E0600, // 0007 IMPORT R3 K3
0xA4120800, // 0008 IMPORT R4 K4
0x8C140705, // 0009 GETMET R5 R3 K5
0x7C140200, // 000A CALL R5 1
0xA8020064, // 000B EXBLK 0 #0071
0x8C180306, // 000C GETMET R6 R1 K6
0x58200007, // 000D LDCONST R8 K7
0x7C180400, // 000E CALL R6 2
0x741A0003, // 000F JMPT R6 #0014
0x8C180306, // 0010 GETMET R6 R1 K6
0x58200008, // 0011 LDCONST R8 K8
0x7C180400, // 0012 CALL R6 2
0x781A001C, // 0013 JMPF R6 #0031
0x8C180306, // 0014 GETMET R6 R1 K6
0x58200007, // 0015 LDCONST R8 K7
0x7C180400, // 0016 CALL R6 2
0x781A0006, // 0017 JMPF R6 #001F
0x88180109, // 0018 GETMBR R6 R0 K9
0x601C0009, // 0019 GETGBL R7 G9
0x8C20030A, // 001A GETMET R8 R1 K10
0x58280007, // 001B LDCONST R10 K7
0x7C200400, // 001C CALL R8 2
0x7C1C0200, // 001D CALL R7 1
0x901A0E07, // 001E SETMBR R6 K7 R7
0x8C180306, // 001F GETMET R6 R1 K6
0x58200008, // 0020 LDCONST R8 K8
0x7C180400, // 0021 CALL R6 2
0x781A0006, // 0022 JMPF R6 #002A
0x88180109, // 0023 GETMBR R6 R0 K9
0x601C0009, // 0024 GETGBL R7 G9
0x8C20030A, // 0025 GETMET R8 R1 K10
0x58280008, // 0026 LDCONST R10 K8
0x7C200400, // 0027 CALL R8 2
0x7C1C0200, // 0028 CALL R7 1
0x901A1007, // 0029 SETMBR R6 K8 R7
0x88180109, // 002A GETMBR R6 R0 K9
0x8C180D0B, // 002B GETMET R6 R6 K11
0x7C180200, // 002C CALL R6 1
0x8C18030C, // 002D GETMET R6 R1 K12
0x5820000D, // 002E LDCONST R8 K13
0x7C180400, // 002F CALL R6 2
0x7002003D, // 0030 JMP #006F
0x8C180306, // 0031 GETMET R6 R1 K6
0x5820000E, // 0032 LDCONST R8 K14
0x7C180400, // 0033 CALL R6 2
0x781A000C, // 0034 JMPF R6 #0042
0xB81A1E00, // 0035 GETNGBL R6 K15
0x8C180D10, // 0036 GETMET R6 R6 K16
0x60200008, // 0037 GETGBL R8 G8
0xB8262400, // 0038 GETNGBL R9 K18
0x88241313, // 0039 GETMBR R9 R9 K19
0x7C200200, // 003A CALL R8 1
0x00222208, // 003B ADD R8 K17 R8
0x00201114, // 003C ADD R8 R8 K20
0x7C180400, // 003D CALL R6 2
0x8C18030C, // 003E GETMET R6 R1 K12
0x5820000D, // 003F LDCONST R8 K13
0x7C180400, // 0040 CALL R6 2
0x7002002C, // 0041 JMP #006F
0x8C180306, // 0042 GETMET R6 R1 K6
0x58200015, // 0043 LDCONST R8 K21
0x7C180400, // 0044 CALL R6 2
0x781A000C, // 0045 JMPF R6 #0053
0xB81A1E00, // 0046 GETNGBL R6 K15
0x8C180D10, // 0047 GETMET R6 R6 K16
0x60200008, // 0048 GETGBL R8 G8
0xB8262400, // 0049 GETNGBL R9 K18
0x88241313, // 004A GETMBR R9 R9 K19
0x7C200200, // 004B CALL R8 1
0x00222208, // 004C ADD R8 K17 R8
0x00201116, // 004D ADD R8 R8 K22
0x7C180400, // 004E CALL R6 2
0x8C18030C, // 004F GETMET R6 R1 K12
0x5820000D, // 0050 LDCONST R8 K13
0x7C180400, // 0051 CALL R6 2
0x7002001B, // 0052 JMP #006F
0x8C180306, // 0053 GETMET R6 R1 K6
0x58200017, // 0054 LDCONST R8 K23
0x7C180400, // 0055 CALL R6 2
0x781A0017, // 0056 JMPF R6 #006F
0x88180109, // 0057 GETMBR R6 R0 K9
0x88180D18, // 0058 GETMBR R6 R6 K24
0x8C180D19, // 0059 GETMET R6 R6 K25
0x60200009, // 005A GETGBL R8 G9
0x8C24030A, // 005B GETMET R9 R1 K10
0x582C0017, // 005C LDCONST R11 K23
0x7C240400, // 005D CALL R9 2
0x7C200200, // 005E CALL R8 1
0x7C180400, // 005F CALL R6 2
0x4C1C0000, // 0060 LDNIL R7
0x201C0C07, // 0061 NE R7 R6 R7
0x781E0008, // 0062 JMPF R7 #006C
0x881C0109, // 0063 GETMBR R7 R0 K9
0x881C0F18, // 0064 GETMBR R7 R7 K24
0x8C1C0F1A, // 0065 GETMET R7 R7 K26
0x5C240C00, // 0066 MOVE R9 R6
0x7C1C0400, // 0067 CALL R7 2
0x881C0109, // 0068 GETMBR R7 R0 K9
0x881C0F18, // 0069 GETMBR R7 R7 K24
0x8C1C0F1B, // 006A GETMET R7 R7 K27
0x7C1C0200, // 006B CALL R7 1
0x8C1C030C, // 006C GETMET R7 R1 K12
0x5824000D, // 006D LDCONST R9 K13
0x7C1C0400, // 006E CALL R7 2
0xA8040001, // 006F EXBLK 1 1
0x7002001D, // 0070 JMP #008F
0xAC180002, // 0071 CATCH R6 0 2
0x7002001A, // 0072 JMP #008E
0xB8221E00, // 0073 GETNGBL R8 K15
0x8C20111C, // 0074 GETMET R8 R8 K28
0x8C28051D, // 0075 GETMET R10 R2 K29
0x5830001E, // 0076 LDCONST R12 K30
0x5C340C00, // 0077 MOVE R13 R6
0x5C380E00, // 0078 MOVE R14 R7
0x7C280800, // 0079 CALL R10 4
0x582C001F, // 007A LDCONST R11 K31
0x7C200600, // 007B CALL R8 3
0x8C200320, // 007C GETMET R8 R1 K32
0x58280021, // 007D LDCONST R10 K33
0x7C200400, // 007E CALL R8 2
0x8C200322, // 007F GETMET R8 R1 K34
0x7C200200, // 0080 CALL R8 1
0x8C200323, // 0081 GETMET R8 R1 K35
0x8C28051D, // 0082 GETMET R10 R2 K29
0x58300024, // 0083 LDCONST R12 K36
0x5C340C00, // 0084 MOVE R13 R6
0x5C380E00, // 0085 MOVE R14 R7
0x7C280800, // 0086 CALL R10 4
0x7C200400, // 0087 CALL R8 2
0x8C200325, // 0088 GETMET R8 R1 K37
0x88280326, // 0089 GETMBR R10 R1 K38
0x7C200400, // 008A CALL R8 2
0x8C200327, // 008B GETMET R8 R1 K39
0x7C200200, // 008C CALL R8 1
0x70020000, // 008D JMP #008F
0xB0080000, // 008E RAISE 2 R0 R0
0x80000000, // 008F RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: web_add_config_button
********************************************************************/
be_local_closure(Matter_UI_web_add_config_button, /* name */
be_nested_proto(
5, /* nstack */
1, /* 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(webserver),
/* K1 */ be_nested_str_weak(content_send),
/* K2 */ be_nested_str_weak(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27matterc_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E),
/* K3 */ be_nested_str_weak(matter),
/* K4 */ be_nested_str_weak(_LOGO),
/* K5 */ be_nested_str_weak(_X20Configure_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E),
}),
be_str_weak(web_add_config_button),
&be_const_str_solidified,
( &(const binstruction[12]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x8C080301, // 0001 GETMET R2 R1 K1
0x58100002, // 0002 LDCONST R4 K2
0x7C080400, // 0003 CALL R2 2
0x8C080301, // 0004 GETMET R2 R1 K1
0xB8120600, // 0005 GETNGBL R4 K3
0x88100904, // 0006 GETMBR R4 R4 K4
0x7C080400, // 0007 CALL R2 2
0x8C080301, // 0008 GETMET R2 R1 K1
0x58100005, // 0009 LDCONST R4 K5
0x7C080400, // 000A CALL R2 2
0x80000000, // 000B RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: page_qrcode_min_js
********************************************************************/
be_local_closure(Matter_UI_page_qrcode_min_js, /* 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[ 6]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(content_open),
/* K2 */ be_nested_str_weak(text_X2Fjavascript),
/* K3 */ be_nested_str_weak(content_send),
/* K4 */ be_nested_str_weak(matter),
/* K5 */ be_nested_str_weak(_QRCODE_MINJS),
}),
be_str_weak(page_qrcode_min_js),
&be_const_str_solidified,
( &(const binstruction[10]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x8C080301, // 0001 GETMET R2 R1 K1
0x541200C7, // 0002 LDINT R4 200
0x58140002, // 0003 LDCONST R5 K2
0x7C080600, // 0004 CALL R2 3
0x8C080303, // 0005 GETMET R2 R1 K3
0xB8120800, // 0006 GETNGBL R4 K4
0x88100905, // 0007 GETMBR R4 R4 K5
0x7C080400, // 0008 CALL R2 2
0x80000000, // 0009 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: page_part_mgr
********************************************************************/
be_local_closure(Matter_UI_page_part_mgr, /* 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[14]) { /* constants */
/* K0 */ be_nested_str_weak(webserver),
/* K1 */ be_nested_str_weak(string),
/* K2 */ be_nested_str_weak(check_privileged_access),
/* K3 */ be_nested_str_weak(content_start),
/* K4 */ be_nested_str_weak(Matter),
/* K5 */ be_nested_str_weak(content_send_style),
/* K6 */ be_nested_str_weak(content_send),
/* K7 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X20src_X3D_X22qrcode_X2Emin_X2Ejs_X22_X3E_X3C_X2Fscript_X3E),
/* K8 */ be_nested_str_weak(show_enable),
/* K9 */ be_nested_str_weak(show_commissioning_info),
/* K10 */ be_nested_str_weak(show_session_info),
/* K11 */ be_nested_str_weak(content_button),
/* K12 */ be_nested_str_weak(BUTTON_CONFIGURATION),
/* K13 */ be_nested_str_weak(content_stop),
}),
be_str_weak(page_part_mgr),
&be_const_str_solidified,
( &(const binstruction[28]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0xA40A0200, // 0001 IMPORT R2 K1
0x8C0C0302, // 0002 GETMET R3 R1 K2
0x7C0C0200, // 0003 CALL R3 1
0x740E0001, // 0004 JMPT R3 #0007
0x4C0C0000, // 0005 LDNIL R3
0x80040600, // 0006 RET 1 R3
0x8C0C0303, // 0007 GETMET R3 R1 K3
0x58140004, // 0008 LDCONST R5 K4
0x7C0C0400, // 0009 CALL R3 2
0x8C0C0305, // 000A GETMET R3 R1 K5
0x7C0C0200, // 000B CALL R3 1
0x8C0C0306, // 000C GETMET R3 R1 K6
0x58140007, // 000D LDCONST R5 K7
0x7C0C0400, // 000E CALL R3 2
0x8C0C0108, // 000F GETMET R3 R0 K8
0x7C0C0200, // 0010 CALL R3 1
0x780E0003, // 0011 JMPF R3 #0016
0x8C0C0109, // 0012 GETMET R3 R0 K9
0x7C0C0200, // 0013 CALL R3 1
0x8C0C010A, // 0014 GETMET R3 R0 K10
0x7C0C0200, // 0015 CALL R3 1
0x8C0C030B, // 0016 GETMET R3 R1 K11
0x8814030C, // 0017 GETMBR R5 R1 K12
0x7C0C0400, // 0018 CALL R3 2
0x8C0C030D, // 0019 GETMET R3 R1 K13
0x7C0C0200, // 001A CALL R3 1
0x80000000, // 001B RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: Matter_UI
********************************************************************/
be_local_class(Matter_UI,
1,
NULL,
be_nested_map(10,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(init, -1), be_const_closure(Matter_UI_init_closure) },
{ be_const_key_weak(device, -1), be_const_var(0) },
{ be_const_key_weak(web_add_handler, -1), be_const_closure(Matter_UI_web_add_handler_closure) },
{ be_const_key_weak(page_part_ctl, -1), be_const_closure(Matter_UI_page_part_ctl_closure) },
{ be_const_key_weak(show_enable, -1), be_const_closure(Matter_UI_show_enable_closure) },
{ be_const_key_weak(show_commissioning_info, 7), be_const_closure(Matter_UI_show_commissioning_info_closure) },
{ be_const_key_weak(show_session_info, 3), be_const_closure(Matter_UI_show_session_info_closure) },
{ be_const_key_weak(web_add_config_button, 0), be_const_closure(Matter_UI_web_add_config_button_closure) },
{ be_const_key_weak(page_qrcode_min_js, -1), be_const_closure(Matter_UI_page_qrcode_min_js_closure) },
{ be_const_key_weak(page_part_mgr, -1), be_const_closure(Matter_UI_page_part_mgr_closure) },
})),
be_str_weak(Matter_UI)
);
/*******************************************************************/
void be_load_Matter_UI_class(bvm *vm) {
be_pushntvclass(vm, &be_class_Matter_UI);
be_setglobal(vm, "Matter_UI");
be_pop(vm, 1);
}
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,189 @@
/* Solidification of Matter_inspect.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
/********************************************************************
** Solidified function: sort
********************************************************************/
be_local_closure(matter_sort, /* name */
be_nested_proto(
6, /* nstack */
1, /* argc */
0, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 3]) { /* constants */
/* K0 */ be_const_int(1),
/* K1 */ be_const_int(0),
/* K2 */ be_nested_str_weak(stop_iteration),
}),
be_str_weak(sort),
&be_const_str_solidified,
( &(const binstruction[29]) { /* code */
0x60040010, // 0000 GETGBL R1 G16
0x6008000C, // 0001 GETGBL R2 G12
0x5C0C0000, // 0002 MOVE R3 R0
0x7C080200, // 0003 CALL R2 1
0x04080500, // 0004 SUB R2 R2 K0
0x400A0002, // 0005 CONNECT R2 K0 R2
0x7C040200, // 0006 CALL R1 1
0xA8020010, // 0007 EXBLK 0 #0019
0x5C080200, // 0008 MOVE R2 R1
0x7C080000, // 0009 CALL R2 0
0x940C0002, // 000A GETIDX R3 R0 R2
0x5C100400, // 000B MOVE R4 R2
0x24140901, // 000C GT R5 R4 K1
0x78160008, // 000D JMPF R5 #0017
0x04140900, // 000E SUB R5 R4 K0
0x94140005, // 000F GETIDX R5 R0 R5
0x24140A03, // 0010 GT R5 R5 R3
0x78160004, // 0011 JMPF R5 #0017
0x04140900, // 0012 SUB R5 R4 K0
0x94140005, // 0013 GETIDX R5 R0 R5
0x98000805, // 0014 SETIDX R0 R4 R5
0x04100900, // 0015 SUB R4 R4 K0
0x7001FFF4, // 0016 JMP #000C
0x98000803, // 0017 SETIDX R0 R4 R3
0x7001FFEE, // 0018 JMP #0008
0x58040002, // 0019 LDCONST R1 K2
0xAC040200, // 001A CATCH R1 1 0
0xB0080000, // 001B RAISE 2 R0 R0
0x80040000, // 001C RET 1 R0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: inspect
********************************************************************/
be_local_closure(matter_inspect, /* name */
be_nested_proto(
16, /* nstack */
1, /* argc */
0, /* 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(introspect),
/* K2 */ be_nested_str_weak(members),
/* K3 */ be_nested_str_weak(get),
/* K4 */ be_nested_str_weak(function),
/* K5 */ be_nested_str_weak(push),
/* K6 */ be_nested_str_weak(stop_iteration),
/* K7 */ be_nested_str_weak(matter),
/* K8 */ be_nested_str_weak(sort),
/* K9 */ be_nested_str_weak(format),
/* K10 */ be_nested_str_weak(_X27_X25s_X27_X3A_X20_X25s),
/* K11 */ be_nested_str_weak(_X7B),
/* K12 */ be_nested_str_weak(concat),
/* K13 */ be_nested_str_weak(_X2C_X20),
/* K14 */ be_nested_str_weak(_X7D),
/* K15 */ be_nested_str_weak(Exception_X3A),
/* K16 */ be_nested_str_weak(_X7C),
}),
be_str_weak(inspect),
&be_const_str_solidified,
( &(const binstruction[85]) { /* code */
0xA8020044, // 0000 EXBLK 0 #0046
0xA4060000, // 0001 IMPORT R1 K0
0xA40A0200, // 0002 IMPORT R2 K1
0x600C0012, // 0003 GETGBL R3 G18
0x7C0C0000, // 0004 CALL R3 0
0x60100010, // 0005 GETGBL R4 G16
0x8C140502, // 0006 GETMET R5 R2 K2
0x5C1C0000, // 0007 MOVE R7 R0
0x7C140400, // 0008 CALL R5 2
0x7C100200, // 0009 CALL R4 1
0xA802000E, // 000A EXBLK 0 #001A
0x5C140800, // 000B MOVE R5 R4
0x7C140000, // 000C CALL R5 0
0x8C180503, // 000D GETMET R6 R2 K3
0x5C200000, // 000E MOVE R8 R0
0x5C240A00, // 000F MOVE R9 R5
0x7C180600, // 0010 CALL R6 3
0x601C0004, // 0011 GETGBL R7 G4
0x5C200C00, // 0012 MOVE R8 R6
0x7C1C0200, // 0013 CALL R7 1
0x201C0F04, // 0014 NE R7 R7 K4
0x781E0002, // 0015 JMPF R7 #0019
0x8C1C0705, // 0016 GETMET R7 R3 K5
0x5C240A00, // 0017 MOVE R9 R5
0x7C1C0400, // 0018 CALL R7 2
0x7001FFF0, // 0019 JMP #000B
0x58100006, // 001A LDCONST R4 K6
0xAC100200, // 001B CATCH R4 1 0
0xB0080000, // 001C RAISE 2 R0 R0
0xB8120E00, // 001D GETNGBL R4 K7
0x8C100908, // 001E GETMET R4 R4 K8
0x5C180600, // 001F MOVE R6 R3
0x7C100400, // 0020 CALL R4 2
0x5C0C0800, // 0021 MOVE R3 R4
0x60100012, // 0022 GETGBL R4 G18
0x7C100000, // 0023 CALL R4 0
0x60140010, // 0024 GETGBL R5 G16
0x5C180600, // 0025 MOVE R6 R3
0x7C140200, // 0026 CALL R5 1
0xA8020011, // 0027 EXBLK 0 #003A
0x5C180A00, // 0028 MOVE R6 R5
0x7C180000, // 0029 CALL R6 0
0x8C1C0503, // 002A GETMET R7 R2 K3
0x5C240000, // 002B MOVE R9 R0
0x5C280C00, // 002C MOVE R10 R6
0x7C1C0600, // 002D CALL R7 3
0x8C200905, // 002E GETMET R8 R4 K5
0x8C280309, // 002F GETMET R10 R1 K9
0x5830000A, // 0030 LDCONST R12 K10
0x60340008, // 0031 GETGBL R13 G8
0x5C380C00, // 0032 MOVE R14 R6
0x7C340200, // 0033 CALL R13 1
0x60380008, // 0034 GETGBL R14 G8
0x5C3C0E00, // 0035 MOVE R15 R7
0x7C380200, // 0036 CALL R14 1
0x7C280800, // 0037 CALL R10 4
0x7C200400, // 0038 CALL R8 2
0x7001FFED, // 0039 JMP #0028
0x58140006, // 003A LDCONST R5 K6
0xAC140200, // 003B CATCH R5 1 0
0xB0080000, // 003C RAISE 2 R0 R0
0x8C14090C, // 003D GETMET R5 R4 K12
0x581C000D, // 003E LDCONST R7 K13
0x7C140400, // 003F CALL R5 2
0x00161605, // 0040 ADD R5 K11 R5
0x00140B0E, // 0041 ADD R5 R5 K14
0xA8040001, // 0042 EXBLK 1 1
0x80040A00, // 0043 RET 1 R5
0xA8040001, // 0044 EXBLK 1 1
0x7002000D, // 0045 JMP #0054
0xAC040002, // 0046 CATCH R1 0 2
0x7002000A, // 0047 JMP #0053
0x600C0008, // 0048 GETGBL R3 G8
0x5C100200, // 0049 MOVE R4 R1
0x7C0C0200, // 004A CALL R3 1
0x000E1E03, // 004B ADD R3 K15 R3
0x000C0710, // 004C ADD R3 R3 K16
0x60100008, // 004D GETGBL R4 G8
0x5C140400, // 004E MOVE R5 R2
0x7C100200, // 004F CALL R4 1
0x000C0604, // 0050 ADD R3 R3 R4
0x80040600, // 0051 RET 1 R3
0x70020000, // 0052 JMP #0054
0xB0080000, // 0053 RAISE 2 R0 R0
0x80000000, // 0054 RET 0
})
)
);
/*******************************************************************/
/********************************************************************/
/* End of solidification */

View File

@ -0,0 +1,7 @@
/* Solidification of matter.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
/********************************************************************/
/* End of solidification */

View File

@ -14,10 +14,11 @@ import sys
sys.path().push('src/embedded') # allow to import from src/embedded
# globals that need to exist to make compilation succeed
var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,"
var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,udp,"
"lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs,"
"lv_wifi_bars_icon,lv_wifi_bars,"
"_lvgl"
"_lvgl,"
"int64"
for g:string.split(globs, ",")
global.(g) = nil

View File

@ -138,7 +138,7 @@ autoconf_module.init = def (m)
# ####################################################################################################
# Init web handlers
# ####################################################################################################
# Displays a "Autocong" button on the configuration page
# Displays a "Autoconf" button on the configuration page
def web_add_config_button()
import webserver
webserver.content_send("<p><form id=ac action='ac' style='display: block;' method='get'><button>Auto-configuration</button></form></p>")

View File

@ -16,6 +16,6 @@ for filePath in fileList:
# print("Deleting file : ", filePath)
except:
print("Error while deleting file : ", filePath)
cmd = (env["PYTHONEXE"],join("tools","coc","coc"),"-o","generate","src","default",join("..","berry_tasmota","src"),join("..","berry_tasmota","src","solidify"),join("..","berry_mapping","src"),join("..","berry_int64","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src","solidify"),join("..","..","libesp32_lvgl","lv_binding_berry","generate"),"-c",join("default","berry_conf.h"))
cmd = (env["PYTHONEXE"],join("tools","coc","coc"),"-o","generate","src","default",join("..","berry_tasmota","src"),join("..","berry_matter","src","solidify"),join("..","berry_matter","src"),join("..","berry_tasmota","src","solidify"),join("..","berry_mapping","src"),join("..","berry_int64","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src","solidify"),join("..","..","libesp32_lvgl","lv_binding_berry","generate"),"-c",join("default","berry_conf.h"))
returncode = subprocess.call(cmd, shell=False)
os.chdir(CURRENT_DIR)

View File

@ -88,6 +88,11 @@ const char berry_prog[] =
"import debug "
"import solidify "
#endif
#ifdef USE_MATTER_DEVICE
"import matter "
"global.matter_device = matter.Device() "
#endif
;
#endif // USE_BERRY

View File

@ -24,6 +24,9 @@
#include <berry.h>
#include "berry_tasmota.h"
#ifdef USE_MATTER
#include "berry_matter.h"
#endif
#include "be_vm.h"
#include "ZipReadFS.h"
#include "ccronexpr.h"