Skip to content

Commit 0661d7a

Browse files
andy31415andreilitvinbzbarsky-apple
authored
Make DM provider and ember encode errors the same (project-chip#35338)
* The flag of CONFIG_BUILD_FOR_HOST_UNIT_TEST is not actually tied to unit testing. Implement a separate flag to control if we crash on errors for IM/DM checks or not. * Update src/app/common_flags.gni Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * make the flag name singular * Add unit test cluster members * Modified zap and made these attributes optional * Zap regen * Attributes MUST be up to 0x4FFF so needed to switch codes * Update ids enabling * Move around things and add unit test * Update to run unit tests with enforced DM checking * Comment describing the updated options * Fix unit test * Restyle * Kotlin format since it seems different eforcement is going on here * Update src/app/zap-templates/zcl/data-model/chip/test-cluster.xml Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Update examples/all-clusters-app/linux/main-common.cpp Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Remove redundant using * Simplify/shorten code * Move base to 0x3000 for the new attributes for test cluster testing * Restyle * Fix python unit test * Fix all clusters app * Fix unused import in python * Zap regen * Fix cirque * Fix hardcoded paths in TestTimeSyncTrustedtimeSourceRunner.py * Typo fix * Remove extra spacing * Update text * Fix app path --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 6fa2914 commit 0661d7a

File tree

41 files changed

+1388
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1388
-38
lines changed

.github/workflows/tests.yaml

+9-3
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,17 @@ jobs:
475475
mkdir objdir-clone || true
476476
477477
- name: Build Python REPL and example apps
478+
# NOTE: the data-mode-check + check-failure-die is not 100% perfect as different
479+
# encoding sizes for data that keeps changing may alter over time (e.g. anything relating to time
480+
# or resources such as packet counts or other similar counters)
481+
#
482+
# This may result in invalid errors, however for most purposes of our testing, we are unlikely to
483+
# hit such cases so we remain very strict on testing here.
478484
run: |
479485
scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv'
480486
./scripts/run_in_build_env.sh \
481487
"./scripts/build/build_examples.py \
482-
--target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test \
488+
--target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die \
483489
--target linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test \
484490
--target linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test \
485491
--target linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test \
@@ -496,7 +502,7 @@ jobs:
496502
- name: Generate an argument environment file
497503
run: |
498504
echo -n "" >/tmp/test_env.yaml
499-
echo "ALL_CLUSTERS_APP: out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app" >> /tmp/test_env.yaml
505+
echo "ALL_CLUSTERS_APP: out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die/chip-all-clusters-app" >> /tmp/test_env.yaml
500506
echo "CHIP_LOCK_APP: out/linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-lock-app" >> /tmp/test_env.yaml
501507
echo "ENERGY_MANAGEMENT_APP: out/linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-energy-management-app" >> /tmp/test_env.yaml
502508
echo "LIT_ICD_APP: out/linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test/lit-icd-app" >> /tmp/test_env.yaml
@@ -515,7 +521,7 @@ jobs:
515521
mkdir -p out/trace_data
516522
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/controller/python/test/test_scripts/mobile-device-test.py'
517523
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/execute_python_tests.py --env-file /tmp/test_env.yaml --search-directory src/python_testing'
518-
scripts/run_in_python_env.sh out/venv './scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py'
524+
scripts/run_in_python_env.sh out/venv './scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py --all-clusters out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die/chip-all-clusters-app'
519525
scripts/run_in_python_env.sh out/venv './src/python_testing/test_testing/test_TC_ICDM_2_1.py'
520526
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestIdChecks.py'
521527
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestSpecParsingDeviceType.py'

examples/all-clusters-app/all-clusters-common/all-clusters-app.matter

+4
Original file line numberDiff line numberDiff line change
@@ -7307,6 +7307,8 @@ internal cluster UnitTesting = 4294048773 {
73077307
attribute TestGlobalEnum globalEnum = 51;
73087308
attribute TestGlobalStruct globalStruct = 52;
73097309
attribute optional boolean unsupported = 255;
7310+
attribute optional int8u readFailureCode = 12288;
7311+
attribute optional int32u failureInt32U = 12289;
73107312
attribute nullable boolean nullableBoolean = 16384;
73117313
attribute nullable Bitmap8MaskMap nullableBitmap8 = 16385;
73127314
attribute nullable Bitmap16MaskMap nullableBitmap16 = 16386;
@@ -9546,6 +9548,8 @@ endpoint 1 {
95469548
callback attribute clusterErrorBoolean;
95479549
ram attribute globalEnum;
95489550
callback attribute globalStruct;
9551+
ram attribute readFailureCode default = 1;
9552+
callback attribute failureInt32U default = 0;
95499553
ram attribute nullableBoolean default = false;
95509554
ram attribute nullableBitmap8 default = 0;
95519555
ram attribute nullableBitmap16 default = 0;

examples/all-clusters-app/all-clusters-common/all-clusters-app.zap

+32
Original file line numberDiff line numberDiff line change
@@ -23327,6 +23327,38 @@
2332723327
"maxInterval": 65534,
2332823328
"reportableChange": 0
2332923329
},
23330+
{
23331+
"name": "readFailureCode",
23332+
"code": 12288,
23333+
"mfgCode": null,
23334+
"side": "server",
23335+
"type": "int8u",
23336+
"included": 1,
23337+
"storageOption": "RAM",
23338+
"singleton": 0,
23339+
"bounded": 0,
23340+
"defaultValue": "1",
23341+
"reportable": 1,
23342+
"minInterval": 1,
23343+
"maxInterval": 65534,
23344+
"reportableChange": 0
23345+
},
23346+
{
23347+
"name": "failureInt32U",
23348+
"code": 12289,
23349+
"mfgCode": null,
23350+
"side": "server",
23351+
"type": "int32u",
23352+
"included": 1,
23353+
"storageOption": "External",
23354+
"singleton": 0,
23355+
"bounded": 0,
23356+
"defaultValue": "0",
23357+
"reportable": 1,
23358+
"minInterval": 1,
23359+
"maxInterval": 65534,
23360+
"reportableChange": 0
23361+
},
2333023362
{
2333123363
"name": "nullable_boolean",
2333223364
"code": 16384,

examples/all-clusters-app/linux/main-common.cpp

+29-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "ValveControlDelegate.h"
2222
#include "WindowCoveringManager.h"
2323
#include "air-quality-instance.h"
24+
#include "app-common/zap-generated/ids/Clusters.h"
2425
#include "device-energy-management-modes.h"
2526
#include "dishwasher-mode.h"
2627
#include "energy-evse-modes.h"
@@ -39,6 +40,7 @@
3940
#include "tcc-mode.h"
4041
#include "thermostat-delegate-impl.h"
4142
#include "water-heater-mode.h"
43+
4244
#include <Options.h>
4345
#include <app-common/zap-generated/attributes/Accessors.h>
4446
#include <app/CommandHandler.h>
@@ -54,7 +56,6 @@
5456
#include <app/util/att-storage.h>
5557
#include <app/util/attribute-storage.h>
5658
#include <lib/support/CHIPMem.h>
57-
#include <new>
5859
#include <platform/DeviceInstanceInfoProvider.h>
5960
#include <platform/DiagnosticDataProvider.h>
6061
#include <platform/PlatformManager.h>
@@ -72,6 +73,8 @@ using namespace chip;
7273
using namespace chip::app;
7374
using namespace chip::DeviceLayer;
7475

76+
using chip::Protocols::InteractionModel::Status;
77+
7578
namespace {
7679

7780
constexpr char kChipEventFifoPathPrefix[] = "/tmp/chip_all_clusters_fifo_";
@@ -336,3 +339,28 @@ void emberAfThermostatClusterInitCallback(EndpointId endpoint)
336339

337340
SetDefaultDelegate(endpoint, &delegate);
338341
}
342+
343+
Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId,
344+
const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer,
345+
uint16_t maxReadLength)
346+
{
347+
348+
VerifyOrReturnValue(clusterId == Clusters::UnitTesting::Id, Status::Failure);
349+
VerifyOrReturnValue(attributeMetadata != nullptr, Status::Failure);
350+
351+
if (attributeMetadata->attributeId == Clusters::UnitTesting::Attributes::FailureInt32U::Id)
352+
{
353+
uint8_t forced_code = 0;
354+
Status status;
355+
356+
status = Clusters::UnitTesting::Attributes::ReadFailureCode::Get(endpoint, &forced_code);
357+
if (status == Status::Success)
358+
{
359+
status = static_cast<Status>(forced_code);
360+
}
361+
return status;
362+
}
363+
364+
// Finally we just do not support external attributes in all-clusters at this point
365+
return Status::Failure;
366+
}

examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter

+2
Original file line numberDiff line numberDiff line change
@@ -5898,6 +5898,8 @@ internal cluster UnitTesting = 4294048773 {
58985898
attribute TestGlobalEnum globalEnum = 51;
58995899
attribute TestGlobalStruct globalStruct = 52;
59005900
attribute optional boolean unsupported = 255;
5901+
attribute optional int8u readFailureCode = 12288;
5902+
attribute optional int32u failureInt32U = 12289;
59015903
attribute nullable boolean nullableBoolean = 16384;
59025904
attribute nullable Bitmap8MaskMap nullableBitmap8 = 16385;
59035905
attribute nullable Bitmap16MaskMap nullableBitmap16 = 16386;

examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter

+2
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,8 @@ internal cluster UnitTesting = 4294048773 {
19081908
attribute TestGlobalEnum globalEnum = 51;
19091909
attribute TestGlobalStruct globalStruct = 52;
19101910
attribute optional boolean unsupported = 255;
1911+
attribute optional int8u readFailureCode = 12288;
1912+
attribute optional int32u failureInt32U = 12289;
19111913
attribute nullable boolean nullableBoolean = 16384;
19121914
attribute nullable Bitmap8MaskMap nullableBitmap8 = 16385;
19131915
attribute nullable Bitmap16MaskMap nullableBitmap16 = 16386;

scripts/build/build/targets.py

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def BuildHostTarget():
196196
target.AppendModifier('data-model-check', data_model_interface="check").ExceptIfRe('-data-model-(enabled|disabled)')
197197
target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-(check|enabled)')
198198
target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-(check|disabled)')
199+
target.AppendModifier('check-failure-die', data_model_interface="enabled").OnlyIfRe('-data-model-check')
199200

200201
return target
201202

scripts/build/builders/host.py

+6
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE,
323323
enable_dnssd_tests: Optional[bool] = None,
324324
chip_casting_simplified: Optional[bool] = None,
325325
data_model_interface: Optional[bool] = None,
326+
chip_data_model_check_die_on_failure: Optional[bool] = None,
326327
):
327328
super(HostBuilder, self).__init__(
328329
root=os.path.join(root, 'examples', app.ExamplePath()),
@@ -421,6 +422,11 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE,
421422
self.extra_gn_options.append('chip_build_tests=true')
422423
self.extra_gn_options.append('chip_data_model_check_die_on_failure=true')
423424
self.build_command = 'check'
425+
elif chip_data_model_check_die_on_failure is not None:
426+
if chip_data_model_check_die_on_failure:
427+
self.extra_gn_options.append('chip_data_model_check_die_on_failure=true')
428+
else:
429+
self.extra_gn_options.append('chip_data_model_check_die_on_failure=false')
424430

425431
if app == HostApp.EFR32_TEST_RUNNER:
426432
self.build_command = 'runner'

scripts/build/testdata/all_targets_linux_x64.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,b
99
esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing]
1010
genio-lighting-app
1111
linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang]
12-
linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-data-model-check][-data-model-disabled][-data-model-enabled]
12+
linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-data-model-check][-data-model-disabled][-data-model-enabled][-check-failure-die]
1313
linux-x64-efr32-test-runner[-clang]
1414
imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release]
1515
infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage][-trustm]

scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py

+31-18
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,40 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
import argparse
1718
import logging
1819
import os
1920
import signal
2021
import subprocess
2122
import sys
2223
import time
2324

24-
DEFAULT_CHIP_ROOT = os.path.abspath(
25-
os.path.join(os.path.dirname(__file__), '..', '..'))
25+
DEFAULT_CHIP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
26+
27+
DEFAULT_ALL_CLUSTERS = os.path.join(
28+
DEFAULT_CHIP_ROOT,
29+
'out',
30+
'linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test',
31+
'chip-all-clusters-app')
32+
DEFAULT_TEST_RUNNER = os.path.join(DEFAULT_CHIP_ROOT, 'scripts', 'tests', 'run_python_test.py')
33+
DEFAULT_TEST_SCRIPT = os.path.join(DEFAULT_CHIP_ROOT, 'src', 'python_testing', 'TestTimeSyncTrustedTimeSource.py')
2634

2735

2836
class TestDriver:
29-
def __init__(self):
30-
self.app_path = os.path.abspath(os.path.join(DEFAULT_CHIP_ROOT, 'out',
31-
'linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test', 'chip-all-clusters-app'))
32-
self.run_python_test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'run_python_test.py'))
37+
def __init__(self, all_clusters: str, test_runner: str, test_script: str):
38+
self.app_path = all_clusters
39+
self.run_python_test_path = test_runner
40+
self.script_path = test_script
3341

34-
self.script_path = os.path.abspath(os.path.join(
35-
DEFAULT_CHIP_ROOT, 'src', 'python_testing', 'TestTimeSyncTrustedTimeSource.py'))
3642
if not os.path.exists(self.app_path):
37-
msg = 'chip-all-clusters-app not found'
38-
logging.error(msg)
39-
raise FileNotFoundError(msg)
43+
logging.error('%s not found', self.app_path)
44+
raise FileNotFoundError(self.app_path)
4045
if not os.path.exists(self.run_python_test_path):
41-
msg = 'run_python_test.py script not found'
42-
logging.error(msg)
43-
raise FileNotFoundError(msg)
46+
logging.error('%s not found', self.run_python_test_path)
47+
raise FileNotFoundError(self.run_python_test_path)
4448
if not os.path.exists(self.script_path):
45-
msg = 'TestTimeSyncTrustedTimeSource.py script not found'
46-
logging.error(msg)
47-
raise FileNotFoundError(msg)
49+
logging.error('%s not found', self.script_path)
50+
raise FileNotFoundError(self.script_path)
4851

4952
def get_base_run_python_cmd(self, run_python_test_path, app_path, app_args, script_path, script_args):
5053
return f'{str(run_python_test_path)} --app {str(app_path)} --app-args "{app_args}" --script {str(script_path)} --script-args "{script_args}"'
@@ -78,7 +81,17 @@ def main():
7881
base_script_args = '--storage-path admin_storage.json --discriminator 1234 --passcode 20202021'
7982
script_args = base_script_args + ' --commissioning-method on-network --commission-only'
8083

81-
driver = TestDriver()
84+
parser = argparse.ArgumentParser('TimeSyncTrustedTimeSource runner', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
85+
parser.add_argument('--all-clusters', default=DEFAULT_ALL_CLUSTERS, help="All clusters application.")
86+
parser.add_argument('--test-runner', default=DEFAULT_TEST_RUNNER, help="the run_python_test.py script.")
87+
parser.add_argument('--test-script', default=DEFAULT_TEST_SCRIPT, help="The path to the TimeSyncTrustedTimeSource test.")
88+
args = parser.parse_args()
89+
90+
driver = TestDriver(
91+
all_clusters=args.all_clusters,
92+
test_runner=args.test_runner,
93+
test_script=args.test_script,
94+
)
8295
ret = driver.run_test_section(app_args, script_args, factory_reset_all=True)
8396
if ret != 0:
8497
return ret

src/app/util/ember-compatibility-functions.cpp

+15-13
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,21 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b
329329
}
330330

331331
// Read attribute using Ember, if it doesn't have an override.
332+
333+
EmberAfAttributeSearchRecord record;
334+
record.endpoint = aPath.mEndpointId;
335+
record.clusterId = aPath.mClusterId;
336+
record.attributeId = aPath.mAttributeId;
337+
Status status = emAfReadOrWriteAttribute(&record, &attributeMetadata, gEmberAttributeIOBufferSpan.data(),
338+
static_cast<uint16_t>(gEmberAttributeIOBufferSpan.size()),
339+
/* write = */ false);
340+
341+
if (status != Status::Success)
342+
{
343+
return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status);
344+
}
345+
346+
// data available, return the corresponding record
332347
AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport();
333348
ReturnErrorOnFailure(aAttributeReports.GetError());
334349

@@ -349,19 +364,6 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b
349364
.EndOfAttributePathIB();
350365
ReturnErrorOnFailure(err);
351366

352-
EmberAfAttributeSearchRecord record;
353-
record.endpoint = aPath.mEndpointId;
354-
record.clusterId = aPath.mClusterId;
355-
record.attributeId = aPath.mAttributeId;
356-
Status status = emAfReadOrWriteAttribute(&record, &attributeMetadata, gEmberAttributeIOBufferSpan.data(),
357-
static_cast<uint16_t>(gEmberAttributeIOBufferSpan.size()),
358-
/* write = */ false);
359-
360-
if (status != Status::Success)
361-
{
362-
return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status);
363-
}
364-
365367
TLV::TLVWriter * writer = attributeDataIBBuilder.GetWriter();
366368
VerifyOrReturnError(writer != nullptr, CHIP_NO_ERROR);
367369

src/app/zap-templates/zcl/data-model/chip/test-cluster.xml

+8
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ limitations under the License.
203203
<attribute side="server" code="0x0033" define="GLOBAL_ENUM" type="TestGlobalEnum" writable="true">global_enum</attribute>
204204
<attribute side="server" code="0x0034" define="GLOBAL_STRUCT" type="TestGlobalStruct" writable="true">global_struct</attribute>
205205

206+
<!-- These attributes are intended to return internal failures when read.
207+
They are internal SDK-test code that are intended to only run through EMBER interfaces instead of
208+
code-backed support (to be able to test ember-based error paths)
209+
-->
210+
<attribute side="server" code="0x3000" define="INT8U" type="int8u" writable="true" min="1" max="0xcb" default="1" optional="true">readFailureCode</attribute>
211+
<attribute side="server" code="0x3001" define="INT32U" type="int32u" writable="true" default="0" optional="true">failureInt32U</attribute>
212+
213+
206214
<attribute side="server" code="0x4000" define="NULLABLE_BOOLEAN" type="boolean" writable="true" default="false" isNullable="true" optional="false">nullable_boolean</attribute>
207215
<attribute side="server" code="0x4001" define="NULLABLE_BITMAP8" type="Bitmap8MaskMap" writable="true" default="0" isNullable="true" optional="false">nullable_bitmap8</attribute>
208216
<attribute side="server" code="0x4002" define="NULLABLE_BITMAP16" type="Bitmap16MaskMap" writable="true" default="0" isNullable="true" optional="false">nullable_bitmap16</attribute>

0 commit comments

Comments
 (0)