From f0d4c42cdc4d52e556be0443d143a801aa6927cb Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Fri, 5 Nov 2021 19:51:04 -0400 Subject: [PATCH 001/136] added build argument to change CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL (#11486) --- scripts/build_python.sh | 13 +++++++++++-- src/messaging/BUILD.gn | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/scripts/build_python.sh b/scripts/build_python.sh index c2217ef6a0bfa4..cfc565a04b5f64 100755 --- a/scripts/build_python.sh +++ b/scripts/build_python.sh @@ -42,6 +42,7 @@ declare chip_detail_logging=false declare enable_pybindings=false declare chip_mdns declare clusters=true +declare case_retry_delta help() { @@ -57,6 +58,9 @@ Input Options: -c, --clusters_for_ip_commissioning true/false Specify whether to use clusters for IP commissioning. By default it is true. -p, --enable_pybindings EnableValue Specify whether to enable pybindings as python controller. + + -t --time_between_case_retries MRPActiveRetryInterval Specify MRPActiveRetryInterval value + Default is 300 ms " } @@ -84,6 +88,10 @@ while (($#)); do enable_pybindings=$2 shift ;; + --time_between_case_retries | -t) + chip_case_retry_delta=$2 + shift + ;; -*) help echo "Unknown Option \"$1\"" @@ -94,15 +102,16 @@ while (($#)); do done # Print input values -echo "Input values: chip_detail_logging = $chip_detail_logging , chip_mdns = \"$chip_mdns\", enable_pybindings = $enable_pybindings" +echo "Input values: chip_detail_logging = $chip_detail_logging , chip_mdns = \"$chip_mdns\", enable_pybindings = $enable_pybindings, chip_case_retry_delta=\"$chip_case_retry_delta\"" # Ensure we have a compilation environment source "$CHIP_ROOT/scripts/activate.sh" # Generates ninja files [[ -n "$chip_mdns" ]] && chip_mdns_arg="chip_mdns=\"$chip_mdns\"" || chip_mdns_arg="" +[[ -n "$chip_case_retry_delta" ]] && chip_case_retry_arg="chip_case_retry_delta=$chip_case_retry_delta" || chip_case_retry_arg="" -gn --root="$CHIP_ROOT" gen "$OUTPUT_ROOT" --args="chip_detail_logging=$chip_detail_logging enable_pylib=$enable_pybindings enable_rtti=$enable_pybindings chip_use_clusters_for_ip_commissioning=$clusters chip_project_config_include_dirs=[\"//config/python\"] $chip_mdns_arg" +gn --root="$CHIP_ROOT" gen "$OUTPUT_ROOT" --args="chip_detail_logging=$chip_detail_logging enable_pylib=$enable_pybindings enable_rtti=$enable_pybindings chip_use_clusters_for_ip_commissioning=$clusters chip_project_config_include_dirs=[\"//config/python\"] $chip_mdns_arg $chip_case_retry_arg" # Compiles python files # Check pybindings was requested diff --git a/src/messaging/BUILD.gn b/src/messaging/BUILD.gn index 9a99dd9e5f25a8..6b3347ea2ff11e 100644 --- a/src/messaging/BUILD.gn +++ b/src/messaging/BUILD.gn @@ -14,6 +14,19 @@ import("//build_overrides/chip.gni") +declare_args() { + # Allows to change time between retries during the case session + chip_case_retry_delta = "" +} + +defines = [] + +if (chip_case_retry_delta != "") { + defines += [ + "CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL=${chip_case_retry_delta}", + ] +} + static_library("messaging") { output_name = "libMessagingLayer" From 9b93223955d758cd727722bfa78ab1c3fe5e6c80 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 5 Nov 2021 19:51:12 -0400 Subject: [PATCH 002/136] Support empty lists in yaml tests. (#11496) --- .../templates/partials/test_cluster.zapt | 2 +- .../partials/test_cluster_command_value.zapt | 5 +- .../tests/suites/TestClusterComplexTypes.yaml | 12 ++ .../chip-tool/zap-generated/test/Commands.h | 113 ++++++++++++------ 4 files changed, 91 insertions(+), 41 deletions(-) diff --git a/examples/chip-tool/templates/partials/test_cluster.zapt b/examples/chip-tool/templates/partials/test_cluster.zapt index 3c6c6818b88631..62d9180f694aaf 100644 --- a/examples/chip-tool/templates/partials/test_cluster.zapt +++ b/examples/chip-tool/templates/partials/test_cluster.zapt @@ -207,7 +207,7 @@ class {{filename}}: public TestCommand {{/if}} VerifyOrReturn(CheckValue {{~#if isList}}AsListLength("{{>itemValue}}", {{>itemValue}}, {{expectedValue.length}}) - {{else if isArray}}AsList("{{>itemValue}}", {{>itemValue}}, {{expectedValue}}) + {{else if isArray}}AsList("{{>itemValue}}", {{>itemValue}}{{#if expectedValue.length}}, {{expectedValue}}{{/if}}) {{else if (isString type)}}AsString("{{>itemValue}}", {{>itemValue}}, "{{expectedValue}}") {{else}}<{{chipType}}>("{{>itemValue}}", {{>itemValue}}, {{expectedValue}}{{asTypeLiteralSuffix type}}) {{/if}} diff --git a/examples/chip-tool/templates/partials/test_cluster_command_value.zapt b/examples/chip-tool/templates/partials/test_cluster_command_value.zapt index 7c8b74e0d07f06..6d3c3c713c9daf 100644 --- a/examples/chip-tool/templates/partials/test_cluster_command_value.zapt +++ b/examples/chip-tool/templates/partials/test_cluster_command_value.zapt @@ -19,12 +19,15 @@ {{! forceNotList=true because we really want the type of a single item here. Similarly, forceNotOptional=true and forceNotNullable=true because we have accounted for those already. }} + {{#if definedValue.length}} {{zapTypeToEncodableClusterObjectType type ns=ns forceNotList=true forceNotNullable=true forceNotOptional=true}} {{asLowerCamelCase label}}List[{{definedValue.length}}]; {{#each definedValue}} {{>commandValue ns=../ns container=(concat (asLowerCamelCase ../label) "List[" @index "]") definedValue=. type=../type ignore=true}} {{/each}} {{container}}{{#unless ignore}}.{{asLowerCamelCase label}}{{/unless}} = {{asLowerCamelCase label}}List; - + {{else}} + {{container}}{{#unless ignore}}.{{asLowerCamelCase label}}{{/unless}} = chip::app::DataModel::List<{{zapTypeToEncodableClusterObjectType type ns=ns forceNotList=true forceNotNullable=true forceNotOptional=true}}>(); + {{/if}} {{else}} {{#if_is_struct type}} diff --git a/src/app/tests/suites/TestClusterComplexTypes.yaml b/src/app/tests/suites/TestClusterComplexTypes.yaml index e8676697c43a84..8241a66258ba69 100644 --- a/src/app/tests/suites/TestClusterComplexTypes.yaml +++ b/src/app/tests/suites/TestClusterComplexTypes.yaml @@ -253,6 +253,18 @@ tests: - name: "arg1" value: [9, 8, 7, 6, 5, 4, 3, 2, 1] + - label: + "Send Test Command With empty List of INT8U and get an empty list back" + command: "testListInt8UReverseRequest" + arguments: + values: + - name: "arg1" + value: [] + response: + values: + - name: "arg1" + value: [] + - label: "Send Test Command With List of Struct Argument and arg1.b of first item is true" diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index eee8515be32114..64f5774eb13181 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -25644,27 +25644,32 @@ class TestClusterComplexTypes : public TestCommand err = TestSendTestCommandWithListOfInt8uAndGetItReversed_4(); break; case 5: - ChipLogProgress( - chipTool, " ***** Test Step 5 : Send Test Command With List of Struct Argument and arg1.b of first item is true\n"); - err = TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsTrue_5(); + ChipLogProgress(chipTool, + " ***** Test Step 5 : Send Test Command With empty List of INT8U and get an empty list back\n"); + err = TestSendTestCommandWithEmptyListOfInt8uAndGetAnEmptyListBack_5(); break; case 6: ChipLogProgress( - chipTool, - " ***** Test Step 6 : Send Test Command With List of Struct Argument and arg1.b of first item is false\n"); - err = TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsFalse_6(); + chipTool, " ***** Test Step 6 : Send Test Command With List of Struct Argument and arg1.b of first item is true\n"); + err = TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsTrue_6(); break; case 7: - ChipLogProgress(chipTool, " ***** Test Step 7 : Send Test Command with optional arg set.\n"); - err = TestSendTestCommandWithOptionalArgSet_7(); + ChipLogProgress( + chipTool, + " ***** Test Step 7 : Send Test Command With List of Struct Argument and arg1.b of first item is false\n"); + err = TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsFalse_7(); break; case 8: - ChipLogProgress(chipTool, " ***** Test Step 8 : Send Test Command without its optional arg.\n"); - err = TestSendTestCommandWithoutItsOptionalArg_8(); + ChipLogProgress(chipTool, " ***** Test Step 8 : Send Test Command with optional arg set.\n"); + err = TestSendTestCommandWithOptionalArgSet_8(); break; case 9: - ChipLogProgress(chipTool, " ***** Test Step 9 : Send Test Command with optional arg set to null.\n"); - err = TestSendTestCommandWithOptionalArgSetToNull_9(); + ChipLogProgress(chipTool, " ***** Test Step 9 : Send Test Command without its optional arg.\n"); + err = TestSendTestCommandWithoutItsOptionalArg_9(); + break; + case 10: + ChipLogProgress(chipTool, " ***** Test Step 10 : Send Test Command with optional arg set to null.\n"); + err = TestSendTestCommandWithOptionalArgSetToNull_10(); break; } @@ -25677,7 +25682,7 @@ class TestClusterComplexTypes : public TestCommand private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 10; + const uint16_t mTestCount = 11; // // Tests methods @@ -25874,7 +25879,37 @@ class TestClusterComplexTypes : public TestCommand NextTest(); } - CHIP_ERROR TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsTrue_5() + CHIP_ERROR TestSendTestCommandWithEmptyListOfInt8uAndGetAnEmptyListBack_5() + { + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, 1); + + using requestType = chip::app::Clusters::TestCluster::Commands::TestListInt8UReverseRequest::Type; + using responseType = chip::app::Clusters::TestCluster::Commands::TestListInt8UReverseResponse::DecodableType; + + chip::app::Clusters::TestCluster::Commands::TestListInt8UReverseRequest::Type request; + + request.arg1 = chip::app::DataModel::List(); + + auto success = [](void * context, const responseType & data) { + (static_cast(context))->OnSuccessResponse_5(data.arg1); + }; + + auto failure = [](void * context, EmberAfStatus status) { + (static_cast(context))->OnFailureResponse_5(status); + }; + return cluster.InvokeCommand(request, this, success, failure); + } + + void OnFailureResponse_5(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_5(const chip::app::DataModel::DecodableList & arg1) + { + VerifyOrReturn(CheckValueAsList("arg1", arg1)); + NextTest(); + } + + CHIP_ERROR TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsTrue_6() { chip::Controller::TestClusterClusterTest cluster; cluster.Associate(mDevice, 1); @@ -25903,24 +25938,24 @@ class TestClusterComplexTypes : public TestCommand request.arg1 = arg1List; auto success = [](void * context, const responseType & data) { - (static_cast(context))->OnSuccessResponse_5(data.value); + (static_cast(context))->OnSuccessResponse_6(data.value); }; auto failure = [](void * context, EmberAfStatus status) { - (static_cast(context))->OnFailureResponse_5(status); + (static_cast(context))->OnFailureResponse_6(status); }; return cluster.InvokeCommand(request, this, success, failure); } - void OnFailureResponse_5(uint8_t status) { ThrowFailureResponse(); } + void OnFailureResponse_6(uint8_t status) { ThrowFailureResponse(); } - void OnSuccessResponse_5(bool value) + void OnSuccessResponse_6(bool value) { VerifyOrReturn(CheckValue("value", value, true)); NextTest(); } - CHIP_ERROR TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsFalse_6() + CHIP_ERROR TestSendTestCommandWithListOfStructArgumentAndArg1bOfFirstItemIsFalse_7() { chip::Controller::TestClusterClusterTest cluster; cluster.Associate(mDevice, 1); @@ -25949,24 +25984,24 @@ class TestClusterComplexTypes : public TestCommand request.arg1 = arg1List; auto success = [](void * context, const responseType & data) { - (static_cast(context))->OnSuccessResponse_6(data.value); + (static_cast(context))->OnSuccessResponse_7(data.value); }; auto failure = [](void * context, EmberAfStatus status) { - (static_cast(context))->OnFailureResponse_6(status); + (static_cast(context))->OnFailureResponse_7(status); }; return cluster.InvokeCommand(request, this, success, failure); } - void OnFailureResponse_6(uint8_t status) { ThrowFailureResponse(); } + void OnFailureResponse_7(uint8_t status) { ThrowFailureResponse(); } - void OnSuccessResponse_6(bool value) + void OnSuccessResponse_7(bool value) { VerifyOrReturn(CheckValue("value", value, false)); NextTest(); } - CHIP_ERROR TestSendTestCommandWithOptionalArgSet_7() + CHIP_ERROR TestSendTestCommandWithOptionalArgSet_8() { chip::Controller::TestClusterClusterTest cluster; cluster.Associate(mDevice, 1); @@ -25979,18 +26014,18 @@ class TestClusterComplexTypes : public TestCommand auto success = [](void * context, const responseType & data) { (static_cast(context)) - ->OnSuccessResponse_7(data.wasPresent, data.wasNull, data.value, data.originalValue); + ->OnSuccessResponse_8(data.wasPresent, data.wasNull, data.value, data.originalValue); }; auto failure = [](void * context, EmberAfStatus status) { - (static_cast(context))->OnFailureResponse_7(status); + (static_cast(context))->OnFailureResponse_8(status); }; return cluster.InvokeCommand(request, this, success, failure); } - void OnFailureResponse_7(uint8_t status) { ThrowFailureResponse(); } + void OnFailureResponse_8(uint8_t status) { ThrowFailureResponse(); } - void OnSuccessResponse_7(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, + void OnSuccessResponse_8(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, const chip::Optional> & originalValue) { VerifyOrReturn(CheckValue("wasPresent", wasPresent, true)); @@ -26007,7 +26042,7 @@ class TestClusterComplexTypes : public TestCommand NextTest(); } - CHIP_ERROR TestSendTestCommandWithoutItsOptionalArg_8() + CHIP_ERROR TestSendTestCommandWithoutItsOptionalArg_9() { chip::Controller::TestClusterClusterTest cluster; cluster.Associate(mDevice, 1); @@ -26019,18 +26054,18 @@ class TestClusterComplexTypes : public TestCommand auto success = [](void * context, const responseType & data) { (static_cast(context)) - ->OnSuccessResponse_8(data.wasPresent, data.wasNull, data.value, data.originalValue); + ->OnSuccessResponse_9(data.wasPresent, data.wasNull, data.value, data.originalValue); }; auto failure = [](void * context, EmberAfStatus status) { - (static_cast(context))->OnFailureResponse_8(status); + (static_cast(context))->OnFailureResponse_9(status); }; return cluster.InvokeCommand(request, this, success, failure); } - void OnFailureResponse_8(uint8_t status) { ThrowFailureResponse(); } + void OnFailureResponse_9(uint8_t status) { ThrowFailureResponse(); } - void OnSuccessResponse_8(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, + void OnSuccessResponse_9(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, const chip::Optional> & originalValue) { VerifyOrReturn(CheckValue("wasPresent", wasPresent, false)); @@ -26038,7 +26073,7 @@ class TestClusterComplexTypes : public TestCommand NextTest(); } - CHIP_ERROR TestSendTestCommandWithOptionalArgSetToNull_9() + CHIP_ERROR TestSendTestCommandWithOptionalArgSetToNull_10() { chip::Controller::TestClusterClusterTest cluster; cluster.Associate(mDevice, 1); @@ -26051,19 +26086,19 @@ class TestClusterComplexTypes : public TestCommand auto success = [](void * context, const responseType & data) { (static_cast(context)) - ->OnSuccessResponse_9(data.wasPresent, data.wasNull, data.value, data.originalValue); + ->OnSuccessResponse_10(data.wasPresent, data.wasNull, data.value, data.originalValue); }; auto failure = [](void * context, EmberAfStatus status) { - (static_cast(context))->OnFailureResponse_9(status); + (static_cast(context))->OnFailureResponse_10(status); }; return cluster.InvokeCommand(request, this, success, failure); } - void OnFailureResponse_9(uint8_t status) { ThrowFailureResponse(); } + void OnFailureResponse_10(uint8_t status) { ThrowFailureResponse(); } - void OnSuccessResponse_9(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, - const chip::Optional> & originalValue) + void OnSuccessResponse_10(bool wasPresent, const chip::Optional & wasNull, const chip::Optional & value, + const chip::Optional> & originalValue) { VerifyOrReturn(CheckValue("wasPresent", wasPresent, true)); From f4dc388a3fe27407206a8ede2da0263729b82fad Mon Sep 17 00:00:00 2001 From: rgoliver Date: Fri, 5 Nov 2021 19:51:57 -0400 Subject: [PATCH 003/136] RPC: Improve setup instructions for ESP (#11473) Multiple reports of people have incorrect uart setups and problems with CHIP_SHELL interfering with RPC. Create better instructions for ensuring the default configuration is correct. --- examples/all-clusters-app/esp32/README.md | 44 ++++++++++++++++------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/examples/all-clusters-app/esp32/README.md b/examples/all-clusters-app/esp32/README.md index 52a89772ea0fb6..bdc52346378150 100644 --- a/examples/all-clusters-app/esp32/README.md +++ b/examples/all-clusters-app/esp32/README.md @@ -5,15 +5,16 @@ control. --- -- [CHIP ESP32 All Clusters Example](#chip-esp32-all-clusters-example) - - [Supported Devices](#supported-devices) - - [Building the Example Application](#building-the-example-application) - - [Commissioning and cluster control](#commissioning-and-cluster-control) - - [Setting up Python Controller](#setting-up-python-controller) - - [Commissioning over BLE](#commissioning-over-ble) - - [Cluster control](#cluster-control) - - [Flashing app using script](#flashing-app-using-script) - - [Note](#note) +- [CHIP ESP32 All Clusters Example](#chip-esp32-all-clusters-example) + - [Supported Devices](#supported-devices) + - [Building the Example Application](#building-the-example-application) + - [Commissioning and cluster control](#commissioning-and-cluster-control) + - [Setting up Python Controller](#setting-up-python-controller) + - [Commissioning over BLE](#commissioning-over-ble) + - [Cluster control](#cluster-control) + - [Flashing app using script](#flashing-app-using-script) + - [Note](#note) + - [Using the RPC console](#using-the-rpc-console) --- @@ -260,13 +261,30 @@ actual effect of the commands. ## Using the RPC console -Enable RPCs in the build using menuconfig: +You can use the rpc default config to setup everything correctly for RPCs: - $ idf.py menuconfig + $ export SDKCONFIG_DEFAULTS=$PROJECT_ROOT/examples/all-clusters-app/esp32/sdkconfig_m5stack_rpc.defaults + $ rm sdkconfig + $ idf.py fullclean -Enable the RPC library: +Alternatively, Enable RPCs in the build using menuconfig: - Component config → CHIP Core → General Options → Enable Pigweed PRC library + - Enable the RPC library and Disable ENABLE_CHIP_SHELL + + Component config → CHIP Core → General Options → Enable Pigweed PRC library + Component config → CHIP Core → General Options → Disabe CHIP Shell + + - Ensure the UART is correctly configured for your board, for m5stack: + + PW RPC Debug channel → UART port number → 0 + PW RPC Debug channel → UART communication speed → 115200 + PW RPC Debug channel → UART RXD pin number → 3 + PW RPC Debug channel → UART TXD pin number → 1 + +After configuring you can build and flash normally: + + $ idf.py build + $ idf.py flash After flashing a build with RPCs enabled you can use the rpc console to send commands to the device. From e4ef3bc8bdb41e76bf0ab5e1e3156aeb809f0bf1 Mon Sep 17 00:00:00 2001 From: Artur Tynecki <77382963+ATmobica@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:53:33 +0100 Subject: [PATCH 004/136] [Mbed] ConnectivityManager improvements (#11467) * Implement set WiFi AP mode for mbed * Improve IP address setting --- src/platform/mbed/ConnectivityManagerImpl.cpp | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/platform/mbed/ConnectivityManagerImpl.cpp b/src/platform/mbed/ConnectivityManagerImpl.cpp index cded2de30b12f3..1a3ac24fa599d4 100644 --- a/src/platform/mbed/ConnectivityManagerImpl.cpp +++ b/src/platform/mbed/ConnectivityManagerImpl.cpp @@ -92,7 +92,19 @@ bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void) CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) { - return CHIP_ERROR_NOT_IMPLEMENTED; + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); + + if (mWiFiAPMode != val) + { + ChipLogDetail(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val)); + } + + mWiFiAPMode = val; + +exit: + return err; } // ==================== ConnectivityManager Platform Internal Methods ==================== @@ -252,10 +264,10 @@ CHIP_ERROR ConnectivityManagerImpl::OnStationConnected() ChipLogProgress(DeviceLayer, "Event - StationConnected"); } - // Update IPv4 address + // Update IP address SocketAddress address; auto error = mWifiInterface->get_ip_address(&address); - if (error) + if (error != NSAPI_ERROR_OK) { if (mIp4Address != IPAddress::Any) { @@ -268,26 +280,7 @@ CHIP_ERROR ConnectivityManagerImpl::OnStationConnected() ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); ChipLogError(DeviceLayer, "Unnexpected loss of Ip4 address"); } - } - else - { - IPAddress addr; - if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp4Address) - { - mIp4Address = addr; - ChipDeviceEvent event; - event.Type = DeviceEventType::kInternetConnectivityChange; - event.InternetConnectivityChange.IPv4 = kConnectivity_Established; - event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; - ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); - ChipLogProgress(DeviceLayer, "New Ip4 address set: %s", address.get_ip_address()); - } - } - // Update IPv6 address - error = mWifiInterface->get_ipv6_link_local_address(&address); - if (error) - { if (mIp6Address != IPAddress::Any) { // Unnexpected change, forward to the application @@ -303,17 +296,34 @@ CHIP_ERROR ConnectivityManagerImpl::OnStationConnected() else { IPAddress addr; - if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp6Address) + if (address.get_ip_version() == NSAPI_IPv4) { - mIp6Address = addr; - ChipDeviceEvent event; - event.Type = DeviceEventType::kInternetConnectivityChange; - event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; - event.InternetConnectivityChange.IPv6 = kConnectivity_Established; - ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); - ChipLogProgress(DeviceLayer, "New Ip6 address set %s", address.get_ip_address()); + if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp4Address) + { + mIp4Address = addr; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_Established; + event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); + ChipLogProgress(DeviceLayer, "New Ip4 address set: %s", address.get_ip_address()); + } + } + else + { + if (IPAddress::FromString(address.get_ip_address(), addr) && addr != mIp6Address) + { + mIp6Address = addr; + ChipDeviceEvent event; + event.Type = DeviceEventType::kInternetConnectivityChange; + event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; + event.InternetConnectivityChange.IPv6 = kConnectivity_Established; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); + ChipLogProgress(DeviceLayer, "New Ip6 address set %s", address.get_ip_address()); + } } } + return CHIP_NO_ERROR; } From 79371688555173b3d1ea489eae1ed577a67ecfe7 Mon Sep 17 00:00:00 2001 From: Feng LI Date: Fri, 5 Nov 2021 16:58:27 -0700 Subject: [PATCH 005/136] [darwin] Fix build failure for ios simulator (#9559). (#11398) Co-authored-by: Feng LI --- build/toolchain/ios/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/toolchain/ios/BUILD.gn b/build/toolchain/ios/BUILD.gn index 8880a9895480db..c86dfcb83b38d5 100644 --- a/build/toolchain/ios/BUILD.gn +++ b/build/toolchain/ios/BUILD.gn @@ -33,7 +33,7 @@ gcc_toolchain("ios_arm64") { } } -gcc_toolchain("ios_x86_64") { +gcc_toolchain("ios_x64") { toolchain_args = { current_os = "ios" current_cpu = "x86_64" From 09eb37bece8777c457b828e06c17b4ecb73d230b Mon Sep 17 00:00:00 2001 From: C Freeman Date: Fri, 5 Nov 2021 19:59:02 -0400 Subject: [PATCH 006/136] Separate ObjectPool into static and dynamic parts (#11371) * Separate ObjectPool into static and dynamic parts The general goal of this refactor is to separate the static and dynamic parts of the ObjectPool so that developers that support heap allocation can also opt to use static allocation for portions of their code. This refactor maps ObjectPool to the same default types as current (dynamic if heap allocation is allowed, static otherwise). Upcoming refactor PRs: - adding unlocked iterator access so we can use range-based for loops (works more easily with the design of certain part of the SDK stack) - Demonstrating the use of the unsized abstract base type pointer for passing pools of unknown size * Apply suggestions from code review Co-authored-by: Michael Sandstedt * Fix size_t and remove base class. Previous size_t changes broke the build - just using size_t now for all stats. Also remove the base class. The idea with that was to allow this pool to be used with the unsigned base classes in the mdns code. However, it looks like it's causing memory bloat despite the fact that nothing actually uses that base class. So it looks like maybe we just need to refactor to mdns. Co-authored-by: Michael Sandstedt --- src/system/SystemObject.h | 367 +++++++++++++++++++++----------------- 1 file changed, 199 insertions(+), 168 deletions(-) diff --git a/src/system/SystemObject.h b/src/system/SystemObject.h index 6dfcb557009781..f6b26025ae9980 100644 --- a/src/system/SystemObject.h +++ b/src/system/SystemObject.h @@ -60,8 +60,10 @@ namespace System { class Layer; class LayerSockets; class LayerLwIP; -template -class ObjectPool; +template +class ObjectPoolStatic; +template +class ObjectPoolDynamic; /** * @class Object @@ -81,8 +83,10 @@ class ObjectPool; */ class DLL_EXPORT Object { - template - friend class ObjectPool; + template + friend class ObjectPoolStatic; + template + friend class ObjectPoolDynamic; public: Object() : mRefCount(0) @@ -194,21 +198,115 @@ union ObjectArena }; /** + * @class ObjectPoolStatic + * * @brief - * A class template used for allocating Object subclass objects from an ObjectArena<> template union. + * This is the data class for static object pools. * - * @tparam T a subclass of Object to be allocated from the arena. + * @tparam T a subclass of Object to be allocated. * @tparam N a positive integer number of objects of class T to allocate from the arena. */ -template -class ObjectPool +template +class ObjectPoolStatic { public: - void Reset(); + T * TryCreate() + { + T * lReturn = nullptr; + (void) static_cast(lReturn); /* In C++-11, this would be a static_assert that T inherits Object. */ + + size_t lIndex = 0; + for (lIndex = 0; lIndex < N; ++lIndex) + { + T & lObject = reinterpret_cast(mArena.uMemory)[lIndex]; + + if (lObject.TryCreate(sizeof(T))) + { + lReturn = &lObject; + break; + } + } +#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS + size_t lNumInUse = 0; + + if (lReturn != nullptr) + { + lIndex++; + lNumInUse = lIndex; + GetNumObjectsInUse(lIndex, lNumInUse); + } + else + { + lNumInUse = N; + } + + UpdateHighWatermark(lNumInUse); +#endif + return lReturn; + } +#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS + /** + * Return the number of objects in use starting at a given index + * + * @param[in] aStartIndex The index to start counting from; pass 0 to count over + * the whole pool. + * @param[in/out] aNumInUse The number of objects in use. If aStartIndex is not 0, + * the function adds to the counter without resetting it first. + */ + void GetNumObjectsInUse(size_t aStartIndex, size_t & aNumInUse) + { + size_t count = 0; + + for (size_t lIndex = aStartIndex; lIndex < N; ++lIndex) + { + T & lObject = reinterpret_cast(mArena.uMemory)[lIndex]; + + if (lObject.IsRetained()) + { + count++; + } + } + + if (aStartIndex == 0) + { + aNumInUse = 0; + } + + aNumInUse += count; + } + void UpdateHighWatermark(const size_t & aCandidate) + { + size_t lTmp; + while (aCandidate > (lTmp = mHighWatermark)) + { + SYSTEM_OBJECT_HWM_TEST_HOOK(); + (void) __sync_bool_compare_and_swap(&mHighWatermark, lTmp, aCandidate); + } + } + volatile size_t mHighWatermark; +#endif + + void GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark) + { +#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS + size_t lNumInUse; + size_t lHighWatermark; - T * TryCreate(); - void GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark); + GetNumObjectsInUse(0, lNumInUse); + lHighWatermark = mHighWatermark; + if (lNumInUse > CHIP_SYS_STATS_COUNT_MAX) + { + lNumInUse = CHIP_SYS_STATS_COUNT_MAX; + } + if (lHighWatermark > CHIP_SYS_STATS_COUNT_MAX) + { + lHighWatermark = CHIP_SYS_STATS_COUNT_MAX; + } + aNumInUse = static_cast(lNumInUse); + aHighWatermark = static_cast(lHighWatermark); +#endif + } /** * @brief * Run a functor for each active object in the pool @@ -219,19 +317,7 @@ class ObjectPool template bool ForEachActiveObject(Function && function) { -#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - std::lock_guard lock(mMutex); - Object * p = mDummyHead.mNext; - while (p) - { - if (!function(static_cast(p))) - { - return false; - } - p = p->mNext; - } -#else - for (unsigned int i = 0; i < N; ++i) + for (size_t i = 0; i < N; ++i) { T & lObject = reinterpret_cast(mArena.uMemory)[i]; @@ -241,185 +327,130 @@ class ObjectPool return false; } } -#endif return true; } - -private: - friend class TestObject; - -#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - std::mutex mMutex; - Object mDummyHead; -#else - ObjectArena mArena; - + void Reset() + { + memset(mArena.uMemory, 0, N * sizeof(T)); #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS - void GetNumObjectsInUse(unsigned int aStartIndex, unsigned int & aNumInUse); - void UpdateHighWatermark(const unsigned int & aCandidate); - volatile unsigned int mHighWatermark; -#endif + mHighWatermark = 0; #endif + } + ObjectArena mArena; }; -template -inline void ObjectPool::Reset() -{ #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - std::lock_guard lock(mMutex); - Object * p = mDummyHead.mNext; - - while (p) - { - Object * del = p; - p = p->mNext; - delete del; - } - - mDummyHead.mNext = nullptr; -#else - memset(mArena.uMemory, 0, N * sizeof(T)); - -#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS - mHighWatermark = 0; -#endif -#endif -} - /** + * @class ObjectPoolDynamic + * * @brief - * Tries to initially retain the first object in the pool that is not retained. + * This is the data class for dynamic object pools. + * + * @tparam T a subclass of Object to be allocated. */ -template -inline T * ObjectPool::TryCreate() +template +class ObjectPoolDynamic { - T * lReturn = nullptr; +public: + T * TryCreate() + { - (void) static_cast(lReturn); /* In C++-11, this would be a static_assert that T inherits Object. */ + T * newNode = new T(); -#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - T * newNode = new T(); + if (newNode->TryCreate(sizeof(T))) + { + std::lock_guard lock(mMutex); + Object * p = &mDummyHead; + if (p->mNext) + { + p->mNext->mPrev = newNode; + } + newNode->mNext = p->mNext; + p->mNext = newNode; + newNode->mPrev = p; + newNode->mMutexRef = &mMutex; + return newNode; + } + else + { + delete newNode; + return nullptr; + } + } - if (newNode->TryCreate(sizeof(T))) + /** + * @brief + * Run a functor for each active object in the pool + * + * @param function The functor of type `bool (*)(T*)`, return false to break the iteration + * @return bool Returns false if broke during iteration + */ + template + bool ForEachActiveObject(Function && function) { std::lock_guard lock(mMutex); - Object * p = &mDummyHead; - if (p->mNext) + Object * p = mDummyHead.mNext; + while (p) { - p->mNext->mPrev = newNode; + if (!function(static_cast(p))) + { + return false; + } + p = p->mNext; } - newNode->mNext = p->mNext; - p->mNext = newNode; - newNode->mPrev = p; - newNode->mMutexRef = &mMutex; - lReturn = newNode; - } - else - { - delete newNode; + return true; } -#else // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - unsigned int lIndex = 0; - - for (lIndex = 0; lIndex < N; ++lIndex) + void Reset() { - T & lObject = reinterpret_cast(mArena.uMemory)[lIndex]; + std::lock_guard lock(mMutex); + Object * p = mDummyHead.mNext; - if (lObject.TryCreate(sizeof(T))) + while (p) { - lReturn = &lObject; - break; + Object * del = p; + p = p->mNext; + delete del; } - } -#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS - unsigned int lNumInUse = 0; - - if (lReturn != nullptr) - { - lIndex++; - lNumInUse = lIndex; - GetNumObjectsInUse(lIndex, lNumInUse); + mDummyHead.mNext = nullptr; } - else - { - lNumInUse = N; - } - - UpdateHighWatermark(lNumInUse); -#endif + void GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark) {} + std::mutex mMutex; + Object mDummyHead; + friend class TestObject; +}; #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - return lReturn; -} +#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP +template +using ObjectPool = ObjectPoolDynamic; +#else +template +using ObjectPool = ObjectPoolStatic; +#endif -#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS && !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -template -inline void ObjectPool::UpdateHighWatermark(const unsigned int & aCandidate) +enum class ObjectPoolMem { - unsigned int lTmp; + kStatic, +#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP + kDynamic +#endif +}; - while (aCandidate > (lTmp = mHighWatermark)) - { - SYSTEM_OBJECT_HWM_TEST_HOOK(); - (void) __sync_bool_compare_and_swap(&mHighWatermark, lTmp, aCandidate); - } -} +template +class MemTypeObjectPool; -/** - * Return the number of objects in use starting at a given index - * - * @param[in] aStartIndex The index to start counting from; pass 0 to count over - * the whole pool. - * @param[in/out] aNumInUse The number of objects in use. If aStartIndex is not 0, - * the function adds to the counter without resetting it first. - */ -template -inline void ObjectPool::GetNumObjectsInUse(unsigned int aStartIndex, unsigned int & aNumInUse) +template +class MemTypeObjectPool : public ObjectPoolStatic { - unsigned int count = 0; - - for (unsigned int lIndex = aStartIndex; lIndex < N; ++lIndex) - { - T & lObject = reinterpret_cast(mArena.uMemory)[lIndex]; - - if (lObject.IsRetained()) - { - count++; - } - } - - if (aStartIndex == 0) - { - aNumInUse = 0; - } - - aNumInUse += count; -} -#endif // CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS && !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP +}; -template -inline void ObjectPool::GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark) +#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP +template +class MemTypeObjectPool : public ObjectPoolDynamic { -#if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS && !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - unsigned int lNumInUse; - unsigned int lHighWatermark; - - GetNumObjectsInUse(0, lNumInUse); - lHighWatermark = mHighWatermark; - - if (lNumInUse > CHIP_SYS_STATS_COUNT_MAX) - { - lNumInUse = CHIP_SYS_STATS_COUNT_MAX; - } - if (lHighWatermark > CHIP_SYS_STATS_COUNT_MAX) - { - lHighWatermark = CHIP_SYS_STATS_COUNT_MAX; - } - aNumInUse = static_cast(lNumInUse); - aHighWatermark = static_cast(lHighWatermark); +}; #endif -} } // namespace System } // namespace chip From 6b32d93d7e886a714de57adbb3e8d90bdb15a549 Mon Sep 17 00:00:00 2001 From: JasonLiuZhuoCheng Date: Fri, 5 Nov 2021 20:00:06 -0400 Subject: [PATCH 007/136] Cluster command detail page (#11354) * try to find a state where m5stack doesn't bootloop * add back class description * select different cluster, command will remove previous displayed parameter * add responseValueInfo class instead of string split * remove unused variable * Restyled by whitespace * Restyled by google-java-format * Restyled by gn * fix parameter response ui alignment issue * resolve comments * fix format * regenerate clusterInfoMapping.java * resolve comments * merge with master to get pass the check Co-authored-by: Restyled.io --- src/android/CHIPTool/.idea/misc.xml | 9 - .../ClusterDetailFragment.kt | 181 ++++- .../ClusterInteractionFragment.kt | 39 +- .../main/res/layout/cluster_callback_item.xml | 42 ++ .../res/layout/cluster_detail_fragment.xml | 50 +- .../res/layout/cluster_parameter_item.xml | 44 ++ .../app/src/main/res/values/strings.xml | 3 + src/controller/java/BUILD.gn | 1 + .../clusterinfo/ClusterCommandCallback.java | 4 +- .../chip/clusterinfo/CommandResponseInfo.java | 14 + .../java/templates/ClusterInfo-java.zapt | 9 +- .../devicecontroller/ClusterInfoMapping.java | 659 +++++++++++------- 12 files changed, 768 insertions(+), 287 deletions(-) delete mode 100644 src/android/CHIPTool/.idea/misc.xml create mode 100644 src/android/CHIPTool/app/src/main/res/layout/cluster_callback_item.xml create mode 100644 src/android/CHIPTool/app/src/main/res/layout/cluster_parameter_item.xml create mode 100644 src/controller/java/src/chip/clusterinfo/CommandResponseInfo.java diff --git a/src/android/CHIPTool/.idea/misc.xml b/src/android/CHIPTool/.idea/misc.xml deleted file mode 100644 index 37a750962da6f2..00000000000000 --- a/src/android/CHIPTool/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt index d6c84234ea5e38..72f0c0e33ab319 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterDetailFragment.kt @@ -1,37 +1,95 @@ package com.google.chip.chiptool.clusterclient.clusterinteraction import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView +import android.widget.LinearLayout import android.widget.Toast +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.forEach import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope +import chip.clusterinfo.ClusterCommandCallback +import chip.clusterinfo.ClusterInfo +import chip.clusterinfo.CommandInfo +import chip.clusterinfo.CommandResponseInfo +import chip.clusterinfo.DelegatedClusterCallback +import chip.devicecontroller.ChipClusters import chip.devicecontroller.ChipDeviceController +import chip.devicecontroller.ClusterInfoMapping import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R +import kotlinx.android.synthetic.main.cluster_callback_item.view.clusterCallbackDataTv +import kotlinx.android.synthetic.main.cluster_callback_item.view.clusterCallbackNameTv +import kotlinx.android.synthetic.main.cluster_callback_item.view.clusterCallbackTypeTv +import kotlinx.android.synthetic.main.cluster_detail_fragment.view.callbackList +import kotlinx.android.synthetic.main.cluster_detail_fragment.view.clusterAutoCompleteTv +import kotlinx.android.synthetic.main.cluster_detail_fragment.view.commandAutoCompleteTv +import kotlinx.android.synthetic.main.cluster_detail_fragment.view.invokeCommand +import kotlinx.android.synthetic.main.cluster_detail_fragment.view.parameterList +import kotlinx.android.synthetic.main.cluster_parameter_item.view.clusterParameterData +import kotlinx.android.synthetic.main.cluster_parameter_item.view.clusterParameterNameTv +import kotlinx.android.synthetic.main.cluster_parameter_item.view.clusterParameterTypeTv import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel /** * ClusterDetailFragment allows user to pick cluster, command, specify parameters and see * the callback result. */ -class ClusterDetailFragment : Fragment(){ +class ClusterDetailFragment : Fragment() { private val deviceController: ChipDeviceController get() = ChipClient.getDeviceController(requireContext()) - private lateinit var scope: CoroutineScope + private val scope = CoroutineScope(Dispatchers.Main + Job()) + private lateinit var clusterMap: Map + private lateinit var selectedClusterInfo: ClusterInfo + private lateinit var selectedCluster: ChipClusters.BaseChipCluster + private lateinit var selectedCommandCallback: DelegatedClusterCallback + private lateinit var selectedCommandInfo: CommandInfo + private var devicePtr = 0L + private var endpointId = 0 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - scope = viewLifecycleOwner.lifecycleScope - + clusterMap = ClusterInfoMapping().clusterMap + devicePtr = checkNotNull(requireArguments().getLong(DEVICE_PTR_KEY)) + endpointId = checkNotNull(requireArguments().getInt(ENDPOINT_ID_KEY)) return inflater.inflate(R.layout.cluster_detail_fragment, container, false).apply { deviceController.setCompletionListener(GenericChipDeviceListener()) + commandAutoCompleteTv.visibility = View.GONE + clusterAutoCompleteSetup(clusterAutoCompleteTv, commandAutoCompleteTv, parameterList) + commandAutoCompleteSetup(commandAutoCompleteTv, inflater, parameterList, callbackList) + invokeCommand.setOnClickListener { + val commandArguments = HashMap() + parameterList.forEach { + val type = + selectedCommandInfo.commandParameters[it.clusterParameterNameTv.text.toString()]!!.type + val data = castStringToType(it.clusterParameterData.text.toString(), type)!! + + commandArguments[it.clusterParameterNameTv.text.toString()] = data + } + selectedCommandInfo.getCommandFunction() + .invokeCommand(selectedCluster, selectedCommandCallback, commandArguments) + } + } + } + + private fun castStringToType(data: String, type: Class<*>): Any? { + return when (type) { + Int::class.java -> data.toInt() + String::class.java -> data + Boolean::class.java -> data.toBoolean() + else -> null } } @@ -41,8 +99,119 @@ class ClusterDetailFragment : Fragment(){ } } + private fun clusterAutoCompleteSetup( + clusterAutoComplete: AutoCompleteTextView, + commandAutoComplete: AutoCompleteTextView, + parameterList: LinearLayout + ) { + val clusterNameList = constructHint(clusterMap) + val clusterAdapter = + ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, clusterNameList) + clusterAutoComplete.setAdapter(clusterAdapter) + clusterAutoComplete.setOnItemClickListener { parent, view, position, id -> + commandAutoComplete.visibility = View.VISIBLE + // when new cluster is selected, clear the command text and possible parameterList + commandAutoComplete.setText("", false) + parameterList.removeAllViews() + // populate all the commands that belong to the selected cluster + val selectedCluster: String = clusterAutoComplete.adapter.getItem(position).toString() + val commandAdapter = getCommandOptions(selectedCluster) + commandAutoComplete.setAdapter(commandAdapter) + } + } + + private fun commandAutoCompleteSetup( + commandAutoComplete: AutoCompleteTextView, + inflater: LayoutInflater, + parameterList: LinearLayout, + callbackList: LinearLayout + ) { + commandAutoComplete.setOnItemClickListener { parent, view, position, id -> + // when new command is selected, clear all the parameterList + parameterList.removeAllViews() + selectedCluster = selectedClusterInfo.createClusterFunction.create(devicePtr, endpointId) + val selectedCommand: String = commandAutoComplete.adapter.getItem(position).toString() + selectedCommandInfo = selectedClusterInfo.commands[selectedCommand]!! + selectedCommandCallback = selectedCommandInfo.commandCallbackSupplier.get() + populateCommandParameter(inflater, parameterList) + selectedCommandCallback.setCallbackDelegate(object : ClusterCommandCallback { + override fun onSuccess(responseValues: Map) { + showMessage("Command success") + // Populate UI based on response values. We know the types from CommandInfo.getCommandResponses(). + requireActivity().runOnUiThread { + populateCallbackResult( + responseValues, + inflater, + callbackList + ) + } + responseValues.forEach { Log.d(TAG, it.toString()) } + } + + override fun onFailure(exception: Exception) { + showMessage("Command failed") + Log.e(TAG, exception.toString()) + } + }) + } + } + + private fun populateCommandParameter(inflater: LayoutInflater, parameterList: LinearLayout) { + selectedCommandInfo.commandParameters.forEach { (paramName, paramInfo) -> + val param = inflater.inflate(R.layout.cluster_parameter_item, null, false) as ConstraintLayout + param.clusterParameterNameTv.text = "${paramName}" + param.clusterParameterTypeTv.text = "${paramInfo.type}" + parameterList.addView(param) + } + } + + private fun populateCallbackResult( + responseValues: Map, + inflater: LayoutInflater, + callbackList: LinearLayout + ) { + responseValues.forEach { (variableNameType, response) -> + val callback = + inflater.inflate(R.layout.cluster_callback_item, null, false) as ConstraintLayout + callback.clusterCallbackNameTv.text = variableNameType.name + callback.clusterCallbackDataTv.text = response.toString() + callback.clusterCallbackTypeTv.text = variableNameType.type + callbackList.addView(callback) + } + } + + private fun getCommandOptions( + clusterName: String + ): ArrayAdapter { + selectedClusterInfo = clusterMap[clusterName]!! + val commandNameList = constructHint(selectedClusterInfo.commands) + return ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, commandNameList) + } + + private fun constructHint(clusterMap: Map): Array { + return clusterMap.keys.toTypedArray() + } + + override fun onStop() { + super.onStop() + scope.cancel() + } + companion object { private const val TAG = "ClusterDetailFragment" - fun newInstance(): ClusterDetailFragment = ClusterDetailFragment() + private const val ENDPOINT_ID_KEY = "endpoint_id" + private const val DEVICE_PTR_KEY = "device_ptr" + + fun newInstance( + deviceId: Long, + endpointId: Int + ): ClusterDetailFragment { + return ClusterDetailFragment().apply { + arguments = Bundle(2).apply { + putLong(DEVICE_PTR_KEY, deviceId) + putInt(ENDPOINT_ID_KEY, endpointId) + } + } + } } } \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt index 077e2cbf0aed93..27c1b14f5d43cd 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt @@ -1,7 +1,6 @@ package com.google.chip.chiptool.clusterclient.clusterinteraction import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,16 +8,17 @@ import android.widget.Toast import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import chip.clusterinfo.ClusterInfo import chip.devicecontroller.ChipDeviceController -import chip.devicecontroller.ClusterInfoMapping import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel import com.google.chip.chiptool.clusterclient.AddressUpdateFragment import kotlinx.android.synthetic.main.cluster_interaction_fragment.view.endpointList import kotlinx.android.synthetic.main.cluster_interaction_fragment.view.getEndpointListBtn -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class ClusterInteractionFragment : Fragment() { @@ -27,7 +27,7 @@ class ClusterInteractionFragment : Fragment() { private lateinit var scope: CoroutineScope private lateinit var addressUpdateFragment: AddressUpdateFragment - private lateinit var clusterMap: Map + private var devicePtr = 0L override fun onCreateView( inflater: LayoutInflater, @@ -37,17 +37,18 @@ class ClusterInteractionFragment : Fragment() { scope = viewLifecycleOwner.lifecycleScope return inflater.inflate(R.layout.cluster_interaction_fragment, container, false).apply { - deviceController.setCompletionListener(ChipControllerCallback()) + deviceController.setCompletionListener(GenericChipDeviceListener()) + endpointList.visibility = View.GONE getEndpointListBtn.setOnClickListener { scope.launch { + devicePtr = + ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId) showMessage("Retrieving endpoints") endpointList.visibility = View.VISIBLE } } - addressUpdateFragment = childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment - clusterMap = ClusterInfoMapping().clusterMap var dataList: List = ArrayList() // TODO: Dynamically retrieve endpoint information using descriptor cluster // hardcode the endpoint for now @@ -65,23 +66,9 @@ class ClusterInteractionFragment : Fragment() { } } - inner class ChipControllerCallback : GenericChipDeviceListener() { - override fun onConnectDeviceComplete() {} - - override fun onCommissioningComplete(nodeId: Long, errorCode: Int) { - } - - override fun onNotifyChipConnectionClosed() { - Log.d(TAG, "onNotifyChipConnectionClosed") - } - - override fun onCloseBleComplete() { - Log.d(TAG, "onCloseBleComplete") - } - - override fun onError(error: Throwable?) { - Log.d(TAG, "onError: $error") - } + override fun onStop() { + super.onStop() + scope.cancel() } companion object { @@ -104,7 +91,7 @@ class ClusterInteractionFragment : Fragment() { inner class EndpointListener : EndpointAdapter.OnItemClickListener { override fun onItemClick(position: Int) { Toast.makeText(requireContext(), "Item $position clicked", Toast.LENGTH_SHORT).show() - showFragment(ClusterDetailFragment.newInstance()) + showFragment(ClusterDetailFragment.newInstance(devicePtr, position)) } } } \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/res/layout/cluster_callback_item.xml b/src/android/CHIPTool/app/src/main/res/layout/cluster_callback_item.xml new file mode 100644 index 00000000000000..13844ffaa80d12 --- /dev/null +++ b/src/android/CHIPTool/app/src/main/res/layout/cluster_callback_item.xml @@ -0,0 +1,42 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/android/CHIPTool/app/src/main/res/layout/cluster_detail_fragment.xml b/src/android/CHIPTool/app/src/main/res/layout/cluster_detail_fragment.xml index df7ab6283f1ef4..2b9bd001c3b5a5 100644 --- a/src/android/CHIPTool/app/src/main/res/layout/cluster_detail_fragment.xml +++ b/src/android/CHIPTool/app/src/main/res/layout/cluster_detail_fragment.xml @@ -1,8 +1,48 @@ - + android:layout_height="match_parent" + android:padding="16dp" + android:orientation="vertical"> + - \ No newline at end of file + + +