mirror of https://github.com/arendst/Tasmota.git
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:
parent
e8056df1ad
commit
a483991ba3
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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()
|
|
@ -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
|
@ -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
|
@ -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" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
# empty module
|
||||
# allows stand-alone `import path`
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
*/
|
|
@ -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_SUBSCRIPTION, 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
|
@ -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"))
|
||||
|
||||
*/
|
|
@ -0,0 +1,8 @@
|
|||
// force include of module by including this file
|
||||
|
||||
#ifndef __BERRY_MATTER__
|
||||
#define __BERRY_MATTER__
|
||||
|
||||
|
||||
|
||||
#endif // __BERRY_MATTER__
|
|
@ -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
|
||||
|
||||
#-
|
||||
|
||||
-#
|
|
@ -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'}
|
||||
|
||||
-#
|
|
@ -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'}
|
||||
|
||||
-#
|
|
@ -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
|
||||
-#
|
|
@ -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
|
||||
|
||||
|
||||
-#
|
||||
|
|
@ -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}>}>}>
|
||||
|
||||
-#
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
||||
-#
|
|
@ -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"))
|
||||
|
||||
-#
|
|
@ -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()
|
||||
|
||||
-#
|
|
@ -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> Matter %s </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> Matter Passcode </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> Sessions </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> Session %i </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> ", 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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
# placeholder for `import matter` not to fail when running solidification
|
||||
|
||||
var m = module("matter")
|
||||
return m
|
|
@ -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
|
@ -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
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -0,0 +1,7 @@
|
|||
/* Solidification of matter.h */
|
||||
/********************************************************************\
|
||||
* Generated code, don't edit *
|
||||
\********************************************************************/
|
||||
#include "be_constobj.h"
|
||||
/********************************************************************/
|
||||
/* End of solidification */
|
|
@ -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
|
||||
|
|
|
@ -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>")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue