diff --git a/.github/workflows/examples-infineon.yaml b/.github/workflows/examples-infineon.yaml index 7bef8b9552f252..3c709c3354aa0b 100644 --- a/.github/workflows/examples-infineon.yaml +++ b/.github/workflows/examples-infineon.yaml @@ -26,7 +26,7 @@ concurrency: jobs: infineon: name: Infineon examples building - timeout-minutes: 30 + timeout-minutes: 60 runs-on: ubuntu-latest if: github.actor != 'restyled-io[bot]' @@ -72,7 +72,14 @@ jobs: .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ p6 default all-clusters-app \ out/infineon-p6-all-clusters/chip-p6-clusters-example.out - + - name: Build lighting-app example + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh \ + "scripts/build/build_examples.py --no-log-timestamps --target 'infineon-p6-light' build" + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + p6 default light-app \ + out/infineon-p6-light/chip-p6-lighting-example.out - name: Uploading Size Reports uses: actions/upload-artifact@v2 if: ${{ !env.ACT }} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a7a102d81514e2..ce4fecb97314ee 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -246,6 +246,7 @@ "esp32-m5stack-all-clusters-rpc-ipv6only", "infineon-p6-all-clusters", "infineon-p6-lock", + "infineon-p6-light", "linux-arm64-all-clusters", "linux-arm64-all-clusters-ipv6only", "linux-arm64-chip-tool", diff --git a/examples/all-clusters-app/p6/src/main.cpp b/examples/all-clusters-app/p6/src/main.cpp index 68446f6ecf05ab..a943c132dc3620 100644 --- a/examples/all-clusters-app/p6/src/main.cpp +++ b/examples/all-clusters-app/p6/src/main.cpp @@ -89,7 +89,14 @@ int main(void) // Init Chip memory management before the stack chip::Platform::MemoryInit(); - CHIP_ERROR ret = PlatformMgr().InitChipStack(); + CHIP_ERROR ret = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("PersistedStorage::KeyValueStoreMgrImpl().Init() failed"); + appError(ret); + } + + ret = PlatformMgr().InitChipStack(); if (ret != CHIP_NO_ERROR) { P6_LOG("PlatformMgr().InitChipStack() failed"); diff --git a/examples/lighting-app/p6/.gn b/examples/lighting-app/p6/.gn new file mode 100644 index 00000000000000..81cec9d11a421b --- /dev/null +++ b/examples/lighting-app/p6/.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + + import("//args.gni") +} diff --git a/examples/lighting-app/p6/BUILD.gn b/examples/lighting-app/p6/BUILD.gn new file mode 100644 index 00000000000000..6af9db2bffd8b8 --- /dev/null +++ b/examples/lighting-app/p6/BUILD.gn @@ -0,0 +1,109 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/p6.gni") + +import("${build_root}/config/defaults.gni") +import("${p6_sdk_build_root}/p6_executable.gni") +import("${p6_sdk_build_root}/p6_sdk.gni") + +assert(current_os == "freertos") + +p6_project_dir = "${chip_root}/examples/lighting-app/p6" +examples_plat_dir = "${chip_root}/examples/platform/p6" + +declare_args() { + # Dump memory usage at link time. + chip_print_memory_usage = false + + # PIN code for PASE session establishment. + setup_pin_code = 20202021 + + # Monitor & log memory usage at runtime. + enable_heap_monitoring = false +} + +p6_sdk_sources("lighting_app_sdk_sources") { + include_dirs = [ + "${chip_root}/src/platform/P6", + "${p6_project_dir}/include", + "${examples_plat_dir}", + ] + + defines = [ + "BOARD_ID=${p6_board}", + "P6_LOG_ENABLED=1", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setup_pin_code}", + ] + + sources = [ "${p6_project_dir}/include/CHIPProjectConfig.h" ] + + public_configs = [ "${chip_root}/third_party/p6:p6_sdk_config" ] +} + +p6_executable("lighting_app") { + include_dirs = [] + defines = [] + output_name = "chip-p6-lighting-example.out" + + sources = [ + "${examples_plat_dir}/LEDWidget.cpp", + "${examples_plat_dir}/init_p6Platform.cpp", + "src/AppTask.cpp", + "src/ButtonHandler.cpp", + "src/LightingManager.cpp", + "src/ZclCallbacks.cpp", + "src/main.cpp", + ] + + deps = [ + ":lighting_app_sdk_sources", + "${chip_root}/examples/common/QRCode", + "${chip_root}/examples/lighting-app/lighting-common", + "${chip_root}/src/lib", + "${chip_root}/src/setup_payload", + ] + + include_dirs += [ + "include", + "${examples_plat_dir}", + "${p6_project_dir}/include", + ] + + defines = [] + + if (enable_heap_monitoring) { + sources += [ "${examples_plat_dir}/MemMonitoring.cpp" ] + defines += [ "HEAP_MONITORING" ] + } + + if (chip_print_memory_usage) { + ldflags += [ + "-Wl,--print-memory-usage", + "-fstack-usage", + ] + } + + output_dir = root_out_dir +} + +group("p6") { + deps = [ ":lighting_app" ] +} + +group("default") { + deps = [ ":p6" ] +} diff --git a/examples/lighting-app/p6/README.md b/examples/lighting-app/p6/README.md new file mode 100644 index 00000000000000..3ef67d0988b81f --- /dev/null +++ b/examples/lighting-app/p6/README.md @@ -0,0 +1,156 @@ +#CHIP P6 Lighting Example + +An example showing the use of Matter on the Infineon CY8CKIT-062S2-43012 board. + +
+ +- [Matter P6 Lighting Example](#chip-p6-Lighting-example) + - [Introduction](#introduction) + - [Building](#building) + - [Flashing the Application](#flashing-the-application) + - [Commissioning and cluster control](#commissioning-and-cluster-control) + - [Setting up Python Controller](#setting-up-python-controller) + - [Commissioning over BLE](#commissioning-over-ble) + - [Notes](#notes) + - [Cluster control](#cluster-control) + +
+ + + +## Introduction + +The P6 lighting example provides a baseline demonstration of a Light control +device, built using Matter and the Infineon Modustoolbox SDK. It can be +controlled by Matter controller over Wi-Fi network. + +The P6 device can be commissioned over Bluetooth Low Energy where the device and +the Matter controller will exchange security information with the Rendezvous +procedure. Wi-Fi Network credentials are then provided to the P6 device which +will then join the network. + + + +## Building + +- [Modustoolbox Software](https://www.cypress.com/products/modustoolbox) + + Refer to `integrations/docker/images/chip-build-infineon/Dockerfile` or + `scripts/examples/gn_p6_example.sh` for downloading the Software and related + tools. + +- Install some additional tools (likely already present for Matter + developers): \$ sudo apt install gcc g++ clang ninja-build python + python3-venv libssl-dev libavahi-client-dev libglib2.0-dev git cmake + python3-pip + +- Supported hardware: + [CY8CKIT-062S2-43012](https://www.cypress.com/CY8CKIT-062S2-43012) + +* Build the example application: + + $ ./scripts/examples/gn_p6_example.sh ./examples/lighting-app/p6 out/lighting_app_p6 + +- To delete generated executable, libraries and object files use: + + $ cd ~/connectedhomeip + $ rm -rf out/ + + + +## Flashing the Application + +- Put CY8CKIT-062S2-43012 board on KitProg3 CMSIS-DAP Mode by pressing the + `MODE SELECT` button. `KITPROG3 STATUS` LED is ON confirms board is in + proper mode. + +- On the command line: + + $ cd ~/connectedhomeip + $ python3 out/lighting_app_p6/chip-p6-lock-example.flash.py + + + +## Commissioning and cluster control + +Commissioning can be carried out using BLE. + + + +### Setting up Python Controller + +Once P6 is up and running, we need to set up a device controller on Raspberry Pi +4 to perform commissioning and cluster control. + +- Set up python controller. + + $ cd {path-to-connectedhomeip} + $ ./scripts/build_python.sh -m platform + +- Execute the controller. + + $ source ./out/python_env/bin/activate + $ chip-device-ctrl + + + +### Commissioning over BLE + +- Establish the secure session over BLE. + + - chip-device-ctrl > ble-scan + - chip-device-ctrl > connect -ble 3840 20202021 1234 + + Parameters: + 1. Discriminator: 3840 + 2. Setup-pin-code: 20202021 + 3. Node ID: Optional. + If not passed in this command, then it is auto-generated by the controller and + displayed in the output of connect. + The same value should be used in the next commands. + We have chosen a random node ID which is 1234. + +- Add credentials of the Wi-Fi network you want the P6 to connect to, using + the `AddWiFiNetwork` command and then enable the P6 to connect to it using + `EnableWiFiNetwork` command. In this example, we have used `WIFI_SSID` and + `WIFI_PASSWORD` as the SSID and passphrase respectively. + + - chip-device-ctrl > zcl NetworkCommissioning AddWiFiNetwork 1234 0 0 ssid=str:WIFI_SSID credentials=str:WIFI_PASSWORD breadcrumb=0 timeoutMs=1000 + + - chip-device-ctrl > zcl NetworkCommissioning EnableNetwork 1234 0 0 networkID=str:WIFI_SSID breadcrumb=0 timeoutMs=1000 + +- Close the BLE connection to P6, as it is not required hereafter. + + - chip-device-ctrl > close-ble + +- Resolve DNS-SD name and update address of the node in the device controller. + + - chip-device-ctrl > resolve 0 1234 + + + +#### Notes + +Raspberry Pi 4 BLE connection issues can be avoided by running the following +commands. These power cycle the BlueTooth hardware and disable BR/EDR mode. + + $ sudo btmgmt -i hci0 power off + $ sudo btmgmt -i hci0 bredr off + $ sudo btmgmt -i hci0 power on + + + +### Cluster control + +- After successful commissioning, use the OnOff cluster command to toggle + device between On or Off states. + + `chip-device-ctrl > zcl OnOff Off 1234 1 0` + + `chip-device-ctrl > zcl OnOff On 1234 1 0` + +- Cluster OnOff can also be done using the `USER_BTN1` button on the board. + This button is configured with `APP_LIGHT_BUTTON` in `include/AppConfig.h`. + Press `USER_BTN1` on the board to toggle between Light ON and OFF states. + Light ON and OFF can be observed with 'LED9' on the board. This LED is + configured with `LIGHT_STATE_LED` in `include/AppConfig.h`. diff --git a/examples/lighting-app/p6/args.gni b/examples/lighting-app/p6/args.gni new file mode 100644 index 00000000000000..f239efee01e5da --- /dev/null +++ b/examples/lighting-app/p6/args.gni @@ -0,0 +1,20 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("${chip_root}/src/platform/P6/args.gni") + +p6_target_project = + get_label_info(":lighting_app_sdk_sources", "label_no_toolchain") diff --git a/examples/lighting-app/p6/build_overrides b/examples/lighting-app/p6/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/lighting-app/p6/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/lighting-app/p6/include/AppConfig.h b/examples/lighting-app/p6/include/AppConfig.h new file mode 100644 index 00000000000000..5ed6edd44bd594 --- /dev/null +++ b/examples/lighting-app/p6/include/AppConfig.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "cybsp.h" +#include "cyhal.h" + +// ---- Lighting Example App Config ---- + +#define APP_TASK_NAME "APP" + +#define APP_LIGHT_BUTTON_IDX 0 +#define APP_FUNCTION_BUTTON_IDX 1 + +#define APP_LIGHT_BUTTON CYBSP_USER_BTN1 +#define APP_FUNCTION_BUTTON CYBSP_USER_BTN2 +#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50 + +#define APP_BUTTON_PRESSED 0 +#define APP_BUTTON_RELEASED 1 + +#define SYSTEM_STATE_LED CYBSP_USER_LED1 +#define LIGHT_LED CYBSP_USER_LED2 + +// Time it takes in ms for the simulated actuator to move from one +// state to another. +#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 + +// ---- Thread Polling Config ---- +#define THREAD_ACTIVE_POLLING_INTERVAL_MS 100 +#define THREAD_INACTIVE_POLLING_INTERVAL_MS 1000 + +// P6 Logging +#ifdef __cplusplus +extern "C" { +#endif + +void appError(int err); +void P6Log(const char * aFormat, ...); +#define P6_LOG(...) P6Log(__VA_ARGS__) + +#ifdef __cplusplus +} + +#include +void appError(CHIP_ERROR error); +#endif diff --git a/examples/lighting-app/p6/include/AppEvent.h b/examples/lighting-app/p6/include/AppEvent.h new file mode 100644 index 00000000000000..1191e379982d52 --- /dev/null +++ b/examples/lighting-app/p6/include/AppEvent.h @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + enum AppEventTypes + { + kEventType_Button = 0, + kEventType_Timer, + kEventType_Light, + kEventType_Install, + }; + + uint16_t Type; + + union + { + struct + { + uint8_t ButtonIdx; + uint8_t Action; + } ButtonEvent; + struct + { + void * Context; + } TimerEvent; + struct + { + uint8_t Action; + int32_t Actor; + } LightEvent; + }; + + EventHandler Handler; +}; diff --git a/examples/lighting-app/p6/include/AppTask.h b/examples/lighting-app/p6/include/AppTask.h new file mode 100644 index 00000000000000..c7f9a23f48a495 --- /dev/null +++ b/examples/lighting-app/p6/include/AppTask.h @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" +#include "LightingManager.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include +#include + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) + +class AppTask +{ + +public: + CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); + + void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); + void PostEvent(const AppEvent * event); + + void ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction); + +private: + friend AppTask & GetAppTask(void); + + CHIP_ERROR Init(); + + static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(LightingManager::Action_t aAction); + + void CancelTimer(void); + + void DispatchEvent(AppEvent * event); + + static void FunctionTimerEventHandler(AppEvent * aEvent); + static void FunctionHandler(AppEvent * aEvent); + static void LightActionEventHandler(AppEvent * aEvent); + static void TimerEventHandler(TimerHandle_t xTimer); + + static void UpdateClusterState(void); + + void StartTimer(uint32_t aTimeoutMs); + + enum class Function + { + kNoneSelected = 0, + kSoftwareUpdate = 0, + kStartBleAdv = 1, + kFactoryReset = 2, + + kInvalid + }; + + Function mFunction = Function::kNoneSelected; + bool mFunctionTimerActive = false; + bool mSyncClusterToButtonAction = false; + + static AppTask sAppTask; +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/lighting-app/p6/include/ButtonHandler.h b/examples/lighting-app/p6/include/ButtonHandler.h new file mode 100644 index 00000000000000..89b40e33477425 --- /dev/null +++ b/examples/lighting-app/p6/include/ButtonHandler.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "FreeRTOS.h" +#include "cyhal.h" +#include "timers.h" // provides FreeRTOS timer support + +#define GPIO_INTERRUPT_PRIORITY (5) + +class ButtonHandler +{ +public: + static void Init(void); + +private: + static void GpioInit(void); + static void lockbuttonIsr(void * handler_arg, cyhal_gpio_event_t event); + static void functionbuttonIsr(void * handler_arg, cyhal_gpio_event_t event); + static void TimerCallback(TimerHandle_t xTimer); +}; diff --git a/examples/lighting-app/p6/include/CHIPProjectConfig.h b/examples/lighting-app/p6/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..21271e4a31e380 --- /dev/null +++ b/examples/lighting-app/p6/include/CHIPProjectConfig.h @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +/** + * CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY + * + * Enables the use of a hard-coded default Chip device id and credentials if no device id + * is found in Chip NV storage. + * + * This option is for testing only and should be disabled in production releases. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 34 + +// Use a default pairing code if one hasn't been provisioned in flash. +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif + +// For convenience, Chip Security Test Mode can be enabled and the +// requirement for authentication in various protocols can be disabled. +// +// WARNING: These options make it possible to circumvent basic Chip security functionality, +// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. +// +#define CHIP_CONFIG_SECURITY_TEST_MODE 0 +#define CHIP_CONFIG_REQUIRE_AUTH 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION + * + * The product revision number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software revisions. + */ +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_REVISION 1 + +/** + * CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION_STRING + * + * A string identifying the firmware revision running on the device. + * CHIP service currently expects the firmware version to be in the format + * {MAJOR_VERSION}.0d{MINOR_VERSION} + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION_STRING +#define CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION_STRING "0.1ALPHA" +#endif +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for Chip-over-BLE (CHIPoBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC + * + * Enables synchronizing the device's real time clock with a remote Chip Time service + * using the Chip Time Sync protocol. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in Chip NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS + * + * Enable recording UTC timestamps. + */ +#define CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) diff --git a/examples/lighting-app/p6/include/LightingManager.h b/examples/lighting-app/p6/include/LightingManager.h new file mode 100644 index 00000000000000..4cb6fb4647de71 --- /dev/null +++ b/examples/lighting-app/p6/include/LightingManager.h @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support + +#include + +class LightingManager +{ +public: + enum Action_t + { + ON_ACTION = 0, + OFF_ACTION, + + INVALID_ACTION + } Action; + + enum State_t + { + kState_OffInitiated = 0, + kState_OffCompleted, + kState_OnInitiated, + kState_OnCompleted, + } State; + + CHIP_ERROR Init(); + bool IsLightOn(); + void EnableAutoTurnOff(bool aOn); + void SetAutoTurnOffDuration(uint32_t aDurationInSecs); + bool IsActionInProgress(); + bool InitiateAction(int32_t aActor, Action_t aAction); + + typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); + typedef void (*Callback_fn_completed)(Action_t); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + +private: + friend LightingManager & LightMgr(void); + State_t mState = kState_OnCompleted; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + bool mAutoTurnOff; + uint32_t mAutoTurnOffDuration; + bool mAutoTurnOffTimerArmed; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(TimerHandle_t xTimer); + static void AutoTurnOffTimerEventHandler(AppEvent * aEvent); + static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + + static LightingManager sLight; +}; + +inline LightingManager & LightMgr(void) +{ + return LightingManager::sLight; +} diff --git a/examples/lighting-app/p6/src/AppTask.cpp b/examples/lighting-app/p6/src/AppTask.cpp new file mode 100644 index 00000000000000..ddfba4aba5fa9c --- /dev/null +++ b/examples/lighting-app/p6/src/AppTask.cpp @@ -0,0 +1,505 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include "ButtonHandler.h" +#include "LEDWidget.h" +#include "qrcodegen.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 +#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 +#define APP_TASK_STACK_SIZE (4096) +#define APP_TASK_PRIORITY 2 +#define APP_EVENT_QUEUE_SIZE 10 + +namespace { +TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. + +TaskHandle_t sAppTaskHandle; +QueueHandle_t sAppEventQueue; + +LEDWidget sStatusLED; +LEDWidget sLightLED; + +bool sIsWiFiStationProvisioned = false; +bool sIsWiFiStationEnabled = false; +bool sIsWiFiStationConnected = false; +bool sHaveBLEConnections = false; + +uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; +StaticQueue_t sAppEventQueueStruct; + +StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; +StaticTask_t appTaskStruct; +} // namespace + +using namespace chip::TLV; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +AppTask AppTask::sAppTask; + +CHIP_ERROR AppTask::StartAppTask() +{ + sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); + if (sAppEventQueue == NULL) + { + P6_LOG("Failed to allocate app event queue"); + appError(APP_ERROR_EVENT_QUEUE_FAILED); + } + + // Start App task. + sAppTaskHandle = xTaskCreateStatic(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, 1, appStack, &appTaskStruct); + return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; +} + +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Register the callback to init the MDNS server when connectivity is available + PlatformMgr().AddEventHandler( + [](const ChipDeviceEvent * event, intptr_t arg) { + // Restart the server whenever an ip address is renewed + if (event->Type == DeviceEventType::kInternetConnectivityChange) + { + if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established || + event->InternetConnectivityChange.IPv6 == kConnectivity_Established) + { + chip::app::DnssdServer::Instance().StartServer(); + } + } + }, + 0); + // Init ZCL Data Model + chip::Server::GetInstance().Init(); + + // Initialize device attestation config + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); + + // Initialise WSTK buttons PB0 and PB1 (including debounce). + ButtonHandler::Init(); + + // Create FreeRTOS sw timer for Function Selection. + sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = app task obj context + TimerEventHandler // timer callback handler + ); + if (sFunctionTimer == NULL) + { + P6_LOG("funct timer create failed"); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + P6_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_FIRMWARE_REVISION_STRING); + err = LightMgr().Init(); + if (err != CHIP_NO_ERROR) + { + P6_LOG("LightMgr().Init() failed"); + appError(err); + } + + LightMgr().SetCallbacks(ActionInitiated, ActionCompleted); + + // Initialize LEDs + sStatusLED.Init(SYSTEM_STATE_LED); + sLightLED.Init(LIGHT_LED); + sLightLED.Set(LightMgr().IsLightOn()); + UpdateClusterState(); + + ConfigurationMgr().LogDeviceConfig(); + + // Print setup info + PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); + + return err; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + P6_LOG("AppTask.Init() failed"); + appError(err); + } + + P6_LOG("App Task started"); + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + + // Collect connectivity and configuration state from the CHIP stack. Because + // the CHIP event loop is being run in a separate task, the stack must be + // locked while these values are queried. However we use a non-blocking + // lock request (TryLockCHIPStack()) to avoid blocking other UI activities + // when the CHIP task is busy (e.g. with a long crypto operation). + if (PlatformMgr().TryLockChipStack()) + { + sIsWiFiStationEnabled = ConnectivityMgr().IsWiFiStationEnabled(); + sIsWiFiStationConnected = ConnectivityMgr().IsWiFiStationConnected(); + sIsWiFiStationProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); + sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); + PlatformMgr().UnlockChipStack(); + } + + // Update the status LED if factory reset has not been initiated. + // + // If system has "full connectivity", keep the LED On constantly. + // + // If thread and service provisioned, but not attached to the thread network + // yet OR no connectivity to the service OR subscriptions are not fully + // established THEN blink the LED Off for a short period of time. + // + // If the system has ble connection(s) uptill the stage above, THEN blink + // the LEDs at an even rate of 100ms. + // + // Otherwise, blink the LED ON for a very short time. + if (sAppTask.mFunction != Function::kFactoryReset) + { + if (sIsWiFiStationEnabled && sIsWiFiStationProvisioned && !sIsWiFiStationConnected) + { + sStatusLED.Blink(950, 50); + } + else if (sHaveBLEConnections) + { + sStatusLED.Blink(100, 100); + } + else + { + sStatusLED.Blink(50, 950); + } + } + + sStatusLED.Animate(); + sLightLED.Animate(); + } +} + +void AppTask::LightActionEventHandler(AppEvent * aEvent) +{ + bool initiated = false; + LightingManager::Action_t action; + int32_t actor = 0; + CHIP_ERROR err = CHIP_NO_ERROR; + + if (aEvent->Type == AppEvent::kEventType_Light) + { + action = static_cast(aEvent->LightEvent.Action); + actor = aEvent->LightEvent.Actor; + } + else if (aEvent->Type == AppEvent::kEventType_Button) + { + if (LightMgr().IsLightOn()) + { + action = LightingManager::OFF_ACTION; + } + else + { + action = LightingManager::ON_ACTION; + } + actor = AppEvent::kEventType_Button; + } + else + { + err = APP_ERROR_UNHANDLED_EVENT; + } + + if (err == CHIP_NO_ERROR) + { + initiated = LightMgr().InitiateAction(actor, action); + + if (!initiated) + { + P6_LOG("Action is already in progress or active."); + } + } +} + +void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction) +{ + if (btnIdx != APP_LIGHT_BUTTON_IDX && btnIdx != APP_FUNCTION_BUTTON_IDX) + { + return; + } + + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.ButtonIdx = btnIdx; + button_event.ButtonEvent.Action = btnAction; + + if (btnIdx == APP_LIGHT_BUTTON_IDX) + { + button_event.Handler = LightActionEventHandler; + sAppTask.PostEvent(&button_event); + } + else if (btnIdx == APP_FUNCTION_BUTTON_IDX) + { + button_event.Handler = FunctionHandler; + sAppTask.PostEvent(&button_event); + } +} + +void AppTask::TimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = FunctionTimerEventHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, + // initiate factory reset + if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kStartBleAdv) + { + P6_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); + + // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to + // cancel, if required. + sAppTask.StartTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); + + sAppTask.mFunction = Function::kFactoryReset; + + // Turn off all LEDs before starting blink to make sure blink is + // co-ordinated. + sStatusLED.Set(false); + sLightLED.Set(false); + + sStatusLED.Blink(500); + sLightLED.Blink(500); + } + else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kFactoryReset) + { + // Actually trigger Factory Reset + sAppTask.mFunction = Function::kNoneSelected; + ConfigurationMgr().InitiateFactoryReset(); + } +} + +void AppTask::FunctionHandler(AppEvent * aEvent) +{ + // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< + // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the + // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + + // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after + // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. + // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs + // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT + if (aEvent->ButtonEvent.Action == APP_BUTTON_PRESSED) + { + if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kNoneSelected) + { + sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); + sAppTask.mFunction = Function::kStartBleAdv; + } + } + else + { + // If the button was released before factory reset got initiated, start Thread Network + if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kStartBleAdv) + { + sAppTask.CancelTimer(); + sAppTask.mFunction = Function::kNoneSelected; + } + else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == Function::kFactoryReset) + { + // Set Light status LED back to show state of light. + sLightLED.Set(LightMgr().IsLightOn()); + + sAppTask.CancelTimer(); + + // Change the function to none selected since factory reset has been + // canceled. + sAppTask.mFunction = Function::kNoneSelected; + + P6_LOG("Factory Reset has been Canceled"); + } + } +} + +void AppTask::CancelTimer() +{ + if (xTimerStop(sFunctionTimer, 0) == pdFAIL) + { + P6_LOG("app timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } + + mFunctionTimerActive = false; +} + +void AppTask::StartTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sFunctionTimer)) + { + P6_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + P6_LOG("app timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } + + mFunctionTimerActive = true; +} + +void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) +{ + // Action initiated, update the light led + if (aAction == LightingManager::ON_ACTION) + { + P6_LOG("Turning light ON"); + sLightLED.Set(true); + } + else if (aAction == LightingManager::OFF_ACTION) + { + P6_LOG("Turning light OFF"); + sLightLED.Set(false); + } + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } +} + +void AppTask::ActionCompleted(LightingManager::Action_t aAction) +{ + // action has been completed bon the light + if (aAction == LightingManager::ON_ACTION) + { + P6_LOG("Light ON"); + } + else if (aAction == LightingManager::OFF_ACTION) + { + P6_LOG("Light OFF"); + } + + if (sAppTask.mSyncClusterToButtonAction) + { + UpdateClusterState(); + sAppTask.mSyncClusterToButtonAction = false; + } +} + +void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Light; + event.LightEvent.Actor = aActor; + event.LightEvent.Action = aAction; + event.Handler = LightActionEventHandler; + PostEvent(&event); +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + BaseType_t status; + if (xPortIsInsideInterrupt()) + { + BaseType_t higherPrioTaskWoken = pdFALSE; + status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); + +#ifdef portYIELD_FROM_ISR + portYIELD_FROM_ISR(higherPrioTaskWoken); +#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + portEND_SWITCHING_ISR(higherPrioTaskWoken); +#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR +#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" +#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + } + else + { + status = xQueueSend(sAppEventQueue, aEvent, 1); + } + + if (!status) + P6_LOG("Failed to post event to app task event queue"); + } + else + { + P6_LOG("Event Queue is NULL should never happen"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + if (aEvent->Handler) + { + aEvent->Handler(aEvent); + } + else + { + P6_LOG("Event received with no handler. Dropping event."); + } +} + +void AppTask::UpdateClusterState(void) +{ + uint8_t newValue = LightMgr().IsLightOn(); + + // write the new on/off value + EmberAfStatus status = emberAfWriteAttribute(1, ZCL_ON_OFF_CLUSTER_ID, ZCL_ON_OFF_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, + (uint8_t *) &newValue, ZCL_BOOLEAN_ATTRIBUTE_TYPE); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + P6_LOG("ERR: updating on/off %x", status); + } +} diff --git a/examples/lighting-app/p6/src/ButtonHandler.cpp b/examples/lighting-app/p6/src/ButtonHandler.cpp new file mode 100644 index 00000000000000..729939ba56f1f0 --- /dev/null +++ b/examples/lighting-app/p6/src/ButtonHandler.cpp @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ButtonHandler.h" +#include "AppConfig.h" +#include "AppTask.h" + +namespace { +constexpr int kButtonCount = 2; + +TimerHandle_t buttonTimers[kButtonCount]; // FreeRTOS timers used for debouncing +// buttons. Array to hold handles to +// the created timers. + +} // namespace + +void ButtonHandler::Init(void) +{ + GpioInit(); + // Create FreeRTOS sw timers for debouncing buttons. + for (uint8_t i = 0; i < kButtonCount; i++) + { + buttonTimers[i] = xTimerCreate("BtnTmr", // Just a text name, not used by the RTOS kernel + APP_BUTTON_DEBOUNCE_PERIOD_MS, // timer period + false, // no timer reload (==one-shot) + (void *) (int) i, // init timer id = button index + TimerCallback // timer callback handler (all buttons use + // the same timer cn function) + ); + } +} + +void ButtonHandler::GpioInit(void) +{ + cy_rslt_t result = CY_RSLT_SUCCESS; + // Set up button GPIOs to input with pullups. + result = cyhal_gpio_init(APP_LIGHT_BUTTON, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_PULLUP, CYBSP_BTN_OFF); + if (result != CY_RSLT_SUCCESS) + { + printf(" cyhal_gpio_init failed for APP_LOCK_BUTTON\r\n"); + } + result = cyhal_gpio_init(APP_FUNCTION_BUTTON, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_PULLUP, CYBSP_BTN_OFF); + if (result != CY_RSLT_SUCCESS) + { + printf(" cyhal_gpio_init failed for APP_FUNCTION_BUTTON\r\n"); + } + /* Configure GPIO interrupt. */ + cyhal_gpio_register_callback(APP_LIGHT_BUTTON, lockbuttonIsr, NULL); + cyhal_gpio_register_callback(APP_FUNCTION_BUTTON, functionbuttonIsr, NULL); + cyhal_gpio_enable_event(APP_LIGHT_BUTTON, CYHAL_GPIO_IRQ_FALL, GPIO_INTERRUPT_PRIORITY, true); + cyhal_gpio_enable_event(APP_FUNCTION_BUTTON, CYHAL_GPIO_IRQ_FALL, GPIO_INTERRUPT_PRIORITY, true); +} +void ButtonHandler::lockbuttonIsr(void * handler_arg, cyhal_gpio_event_t event) +{ + portBASE_TYPE taskWoken = pdFALSE; + xTimerStartFromISR(buttonTimers[APP_LIGHT_BUTTON_IDX], &taskWoken); +} + +void ButtonHandler::functionbuttonIsr(void * handler_arg, cyhal_gpio_event_t event) +{ + portBASE_TYPE taskWoken = pdFALSE; + xTimerStartFromISR(buttonTimers[APP_FUNCTION_BUTTON_IDX], &taskWoken); +} + +void ButtonHandler::TimerCallback(TimerHandle_t xTimer) +{ + // Get the button index of the expired timer and call button event helper. + uint32_t timerId; + uint8_t buttonevent = 0; + timerId = (uint32_t) pvTimerGetTimerID(xTimer); + if (timerId) + { + buttonevent = cyhal_gpio_read(APP_FUNCTION_BUTTON); + } + else + { + buttonevent = cyhal_gpio_read(APP_LIGHT_BUTTON); + } + GetAppTask().ButtonEventHandler(timerId, (buttonevent) ? APP_BUTTON_PRESSED : APP_BUTTON_RELEASED); +} diff --git a/examples/lighting-app/p6/src/LightingManager.cpp b/examples/lighting-app/p6/src/LightingManager.cpp new file mode 100644 index 00000000000000..b2db66900c8db6 --- /dev/null +++ b/examples/lighting-app/p6/src/LightingManager.cpp @@ -0,0 +1,225 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LightingManager.h" + +#include "AppConfig.h" +#include "AppTask.h" +#include + +LightingManager LightingManager::sLight; + +TimerHandle_t sLightTimer; + +CHIP_ERROR LightingManager::Init() +{ + // Create FreeRTOS sw timer for light timer. + sLightTimer = xTimerCreate("lightTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = light obj context + TimerEventHandler // timer callback handler + ); + + if (sLightTimer == NULL) + { + P6_LOG("sLockTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + mState = kState_OffCompleted; + mAutoTurnOffTimerArmed = false; + mAutoTurnOff = false; + mAutoTurnOffDuration = 0; + + return CHIP_NO_ERROR; +} + +void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +bool LightingManager::IsActionInProgress() +{ + return (mState == kState_OffInitiated || mState == kState_OnInitiated); +} + +bool LightingManager::IsLightOn() +{ + return (mState == kState_OnCompleted); +} + +void LightingManager::EnableAutoTurnOff(bool aOn) +{ + mAutoTurnOff = aOn; +} + +void LightingManager::SetAutoTurnOffDuration(uint32_t aDurationInSecs) +{ + mAutoTurnOffDuration = aDurationInSecs; +} + +bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) +{ + bool action_initiated = false; + State_t new_state; + + // Initiate Turn On/Off Action only when the previous one is complete. + if (mState == kState_OffCompleted && aAction == ON_ACTION) + { + action_initiated = true; + + new_state = kState_OnInitiated; + } + else if (mState == kState_OnCompleted && aAction == OFF_ACTION) + { + action_initiated = true; + + new_state = kState_OffInitiated; + } + + if (action_initiated) + { + if (mAutoTurnOffTimerArmed && new_state == kState_OffInitiated) + { + // If auto turn off timer has been armed and someone initiates turning off, + // cancel the timer and continue as normal. + mAutoTurnOffTimerArmed = false; + + CancelTimer(); + } + + StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); + + // Since the timer started successfully, update the state and trigger callback + mState = new_state; + + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + } + + return action_initiated; +} + +void LightingManager::StartTimer(uint32_t aTimeoutMs) +{ + if (xTimerIsTimerActive(sLightTimer)) + { + P6_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sLightTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) + { + P6_LOG("sLockTimer timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void LightingManager::CancelTimer(void) +{ + if (xTimerStop(sLightTimer, 0) == pdFAIL) + { + P6_LOG("sLightTimer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } +} + +void LightingManager::TimerEventHandler(TimerHandle_t xTimer) +{ + // Get light obj context from timer id. + LightingManager * light = static_cast(pvTimerGetTimerID(xTimer)); + + // The timer event handler will be called in the context of the timer task + // once sLightTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = light; + if (light->mAutoTurnOffTimerArmed) + { + event.Handler = AutoTurnOffTimerEventHandler; + } + else + { + event.Handler = ActuatorMovementTimerEventHandler; + } + GetAppTask().PostEvent(&event); +} + +void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = 0; + + // Make sure auto turn off timer is still armed. + if (!light->mAutoTurnOffTimerArmed) + { + return; + } + + light->mAutoTurnOffTimerArmed = false; + + P6_LOG("Auto Turn Off has been triggered!"); + + light->InitiateAction(actor, OFF_ACTION); +} + +void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action_t actionCompleted = INVALID_ACTION; + + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + + if (light->mState == kState_OffInitiated) + { + light->mState = kState_OffCompleted; + actionCompleted = OFF_ACTION; + } + else if (light->mState == kState_OnInitiated) + { + light->mState = kState_OnCompleted; + actionCompleted = ON_ACTION; + } + + if (actionCompleted != INVALID_ACTION) + { + if (light->mActionCompleted_CB) + { + light->mActionCompleted_CB(actionCompleted); + } + + if (light->mAutoTurnOff && actionCompleted == ON_ACTION) + { + // Start the timer for auto turn off + light->StartTimer(light->mAutoTurnOffDuration * 1000); + + light->mAutoTurnOffTimerArmed = true; + + P6_LOG("Auto Turn off enabled. Will be triggered in %u seconds", light->mAutoTurnOffDuration); + } + } +} diff --git a/examples/lighting-app/p6/src/ZclCallbacks.cpp b/examples/lighting-app/p6/src/ZclCallbacks.cpp new file mode 100644 index 00000000000000..8cb273ce51e3fd --- /dev/null +++ b/examples/lighting-app/p6/src/ZclCallbacks.cpp @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements the handler for data model messages. + */ + +#include "AppConfig.h" +#include "LightingManager.h" + +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app::Clusters; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, + uint16_t size, uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + LightMgr().InitiateAction(AppEvent::kEventType_Light, *value ? LightingManager::ON_ACTION : LightingManager::OFF_ACTION); + } + else if (clusterId == LevelControl::Id) + { + ChipLogProgress(Zcl, + "Level Control attribute ID: " ChipLogFormatMEI " Type: %" PRIu8 " Value: %" PRIu16 ", length %" PRIu16, + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == ColorControl::Id) + { + ChipLogProgress(Zcl, + "Color Control attribute ID: " ChipLogFormatMEI " Type: %" PRIu8 " Value: %" PRIu16 ", length %" PRIu16, + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == OnOffSwitchConfiguration::Id) + { + ChipLogProgress(Zcl, + "OnOff Switch Configuration attribute ID: " ChipLogFormatMEI " Type: %" PRIu8 " Value: %" PRIu16 + ", length %" PRIu16, + ChipLogValueMEI(attributeId), type, *value, size); + + // WIP Apply attribute change to Light + } + else if (clusterId == Identify::Id) + { + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %" PRIu8 " Value: %" PRIu16 ", length %" PRIu16, + ChipLogValueMEI(attributeId), type, *value, size); + } +} + +/** @brief OnOff Cluster Init + * + * This function is called when a specific cluster is initialized. It gives the + * application an opportunity to take care of cluster initialization procedures. + * It is called exactly once for each endpoint where cluster is present. + * + * @param endpoint Ver.: always + * + * TODO Issue #3841 + * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster + * attributes to the default value. + * The logic here expects something similar to the deprecated Plugins callback + * emberAfPluginOnOffClusterServerPostInitCallback. + * + */ +void emberAfOnOffClusterInitCallback(EndpointId endpoint) +{ + // TODO: implement any additional Cluster Server init actions +} diff --git a/examples/lighting-app/p6/src/main.cpp b/examples/lighting-app/p6/src/main.cpp new file mode 100644 index 00000000000000..7d493daff2a25e --- /dev/null +++ b/examples/lighting-app/p6/src/main.cpp @@ -0,0 +1,128 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "AppConfig.h" +#include "init_p6Platform.h" +#include + +#ifdef HEAP_MONITORING +#include "MemMonitoring.h" +#endif + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +volatile int apperror_cnt; +// ================================================================================ +// App Error +//================================================================================= +void appError(int err) +{ + P6_LOG("!!!!!!!!!!!! App Critical Error: %d !!!!!!!!!!!", err); + portDISABLE_INTERRUPTS(); + while (1) + ; +} + +void appError(CHIP_ERROR error) +{ + appError(static_cast(error.AsInteger())); +} + +// ================================================================================ +// FreeRTOS Callbacks +// ================================================================================ +extern "C" void vApplicationIdleHook(void) +{ + // FreeRTOS Idle callback +} + +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + init_p6Platform(); + +#ifdef HEAP_MONITORING + MemMonitoring::startHeapMonitoring(); +#endif + + P6_LOG("==================================================\r\n"); + P6_LOG("chip-p6-lighting-example starting\r\n"); + P6_LOG("==================================================\r\n"); + + // Init Chip memory management before the stack + chip::Platform::MemoryInit(); + + CHIP_ERROR ret = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("PersistedStorage::KeyValueStoreMgrImpl().Init() failed"); + appError(ret); + } + + ret = PlatformMgr().InitChipStack(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("PlatformMgr().InitChipStack() failed"); + appError(ret); + } + chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName("P6_LIGHT"); + P6_LOG("Starting Platform Manager Event Loop"); + ret = PlatformMgr().StartEventLoopTask(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("PlatformMgr().StartEventLoopTask() failed"); + appError(ret); + } + ret = GetAppTask().StartAppTask(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("GetAppTask().Init() failed"); + appError(ret); + } + /* Start the FreeRTOS scheduler */ + vTaskStartScheduler(); + + chip::Platform::MemoryShutdown(); + PlatformMgr().StopEventLoopTask(); + PlatformMgr().Shutdown(); + + // Should never get here. + P6_LOG("vTaskStartScheduler() failed"); + appError(ret); +} diff --git a/examples/lighting-app/p6/third_party/connectedhomeip b/examples/lighting-app/p6/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/lighting-app/p6/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/examples/lock-app/p6/include/AppTask.h b/examples/lock-app/p6/include/AppTask.h index 44718ea75a424a..e4da2aba0aa403 100644 --- a/examples/lock-app/p6/include/AppTask.h +++ b/examples/lock-app/p6/include/AppTask.h @@ -80,7 +80,7 @@ class AppTask kInvalid }; - Function mFunction = Function::kInvalid; + Function mFunction = Function::kNoneSelected; bool mFunctionTimerActive = false; bool mSyncClusterToButtonAction = false; diff --git a/examples/lock-app/p6/include/BoltLockManager.h b/examples/lock-app/p6/include/BoltLockManager.h index 34aa815af65f13..4c0093b3efd592 100644 --- a/examples/lock-app/p6/include/BoltLockManager.h +++ b/examples/lock-app/p6/include/BoltLockManager.h @@ -59,7 +59,7 @@ class BoltLockManager private: friend BoltLockManager & BoltLockMgr(void); - State mState = State::kLockingCompleted; + State mState = State::kUnlockingCompleted; Callback_fn_initiated mActionInitiated_CB; Callback_fn_completed mActionCompleted_CB; diff --git a/examples/lock-app/p6/src/BoltLockManager.cpp b/examples/lock-app/p6/src/BoltLockManager.cpp index 6499a2104d139e..8f7ee9dd5f1fdf 100644 --- a/examples/lock-app/p6/src/BoltLockManager.cpp +++ b/examples/lock-app/p6/src/BoltLockManager.cpp @@ -43,7 +43,7 @@ CHIP_ERROR BoltLockManager::Init() appError(APP_ERROR_CREATE_TIMER_FAILED); } - mState = State::kLockingCompleted; + mState = State::kUnlockingCompleted; mAutoLockTimerArmed = false; mAutoRelock = false; mAutoLockDuration = 0; diff --git a/examples/lock-app/p6/src/main.cpp b/examples/lock-app/p6/src/main.cpp index 6fe0298cad4c34..aceba9a2183528 100644 --- a/examples/lock-app/p6/src/main.cpp +++ b/examples/lock-app/p6/src/main.cpp @@ -79,9 +79,15 @@ int main(void) // Init Chip memory management before the stack chip::Platform::MemoryInit(); - // chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); - CHIP_ERROR ret = PlatformMgr().InitChipStack(); + CHIP_ERROR ret = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); + if (ret != CHIP_NO_ERROR) + { + P6_LOG("PersistedStorage::KeyValueStoreMgrImpl().Init() failed"); + appError(ret); + } + + ret = PlatformMgr().InitChipStack(); if (ret != CHIP_NO_ERROR) { P6_LOG("PlatformMgr().InitChipStack() failed"); diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index e013bd23a998a8..7d5adf9c0f593f 100644 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -229,6 +229,7 @@ def InfineonTargets(): yield target.Extend('p6-lock', board=InfineonBoard.P6BOARD, app=InfineonApp.LOCK) yield target.Extend('p6-all-clusters', board=InfineonBoard.P6BOARD, app=InfineonApp.ALL_CLUSTERS) + yield target.Extend('p6-light', board=InfineonBoard.P6BOARD, app=InfineonApp.LIGHT) ALL = [] diff --git a/scripts/build/builders/infineon.py b/scripts/build/builders/infineon.py index 7a737c3dc83b67..3c5f1f828afa37 100644 --- a/scripts/build/builders/infineon.py +++ b/scripts/build/builders/infineon.py @@ -20,11 +20,14 @@ class InfineonApp(Enum): LOCK = auto() + LIGHT = auto() ALL_CLUSTERS = auto() def ExampleName(self): if self == InfineonApp.LOCK: return 'lock-app' + elif self == InfineonApp.LIGHT: + return 'lighting-app' elif self == InfineonApp.ALL_CLUSTERS: return 'all-clusters-app' else: @@ -33,6 +36,8 @@ def ExampleName(self): def AppNamePrefix(self): if self == InfineonApp.LOCK: return 'chip-p6-lock-example' + elif self == InfineonApp.LIGHT: + return 'chip-p6-lighting-example' elif self == InfineonApp.ALL_CLUSTERS: return 'chip-p6-clusters-example' else: @@ -43,6 +48,8 @@ def FlashBundleName(self): return 'lock_app.flashbundle.txt' elif self == InfineonApp.ALL_CLUSTERS: return 'clusters_app.flashbundle.txt' + elif self == InfineonApp.LIGHT: + return 'light_app.flashbundle.txt' else: raise Exception('Unknown app type: %r' % self) diff --git a/scripts/build/testdata/all_targets_except_host.txt b/scripts/build/testdata/all_targets_except_host.txt index ba1c11063b90d2..29b96163e85a39 100644 --- a/scripts/build/testdata/all_targets_except_host.txt +++ b/scripts/build/testdata/all_targets_except_host.txt @@ -27,6 +27,7 @@ esp32-m5stack-all-clusters-ipv6only esp32-m5stack-all-clusters-rpc esp32-m5stack-all-clusters-rpc-ipv6only infineon-p6-all-clusters +infineon-p6-light infineon-p6-lock mbed-CY8CPROTO_062_4343W-all-clusters-debug (NOGLOB: Compile only for debugging purpose - https://os.mbed.com/docs/mbed-os/latest/program-setup/build-profiles-and-rules.html) mbed-CY8CPROTO_062_4343W-all-clusters-develop (NOGLOB: Compile only for debugging purpose - https://os.mbed.com/docs/mbed-os/latest/program-setup/build-profiles-and-rules.html) diff --git a/scripts/build/testdata/build_all_except_host.txt b/scripts/build/testdata/build_all_except_host.txt index 734f2b84915638..fcd76ac888f211 100644 --- a/scripts/build/testdata/build_all_except_host.txt +++ b/scripts/build/testdata/build_all_except_host.txt @@ -272,6 +272,9 @@ idf.py -C examples/all-clusters-app/esp32 -B {out}/esp32-m5stack-all-clusters-rp # Generating infineon-p6-all-clusters gn gen --check --fail-on-unused-args --root={root}/examples/all-clusters-app/p6 '--args=p6_board="CY8CKIT-062S2-43012"' {out}/infineon-p6-all-clusters +# Generating infineon-p6-light +gn gen --check --fail-on-unused-args --root={root}/examples/lighting-app/p6 '--args=p6_board="CY8CKIT-062S2-43012"' {out}/infineon-p6-light + # Generating infineon-p6-lock gn gen --check --fail-on-unused-args --root={root}/examples/lock-app/p6 '--args=p6_board="CY8CKIT-062S2-43012"' {out}/infineon-p6-lock @@ -679,6 +682,9 @@ idf.py -C examples/all-clusters-app/esp32 -B {out}/esp32-m5stack-all-clusters-rp # Building infineon-p6-all-clusters ninja -C {out}/infineon-p6-all-clusters +# Building infineon-p6-light +ninja -C {out}/infineon-p6-light + # Building infineon-p6-lock ninja -C {out}/infineon-p6-lock diff --git a/scripts/build/testdata/glob_star_targets_except_host.txt b/scripts/build/testdata/glob_star_targets_except_host.txt index fce80642e1562a..c14ea7f7f87879 100644 --- a/scripts/build/testdata/glob_star_targets_except_host.txt +++ b/scripts/build/testdata/glob_star_targets_except_host.txt @@ -27,6 +27,7 @@ esp32-m5stack-all-clusters-ipv6only esp32-m5stack-all-clusters-rpc esp32-m5stack-all-clusters-rpc-ipv6only infineon-p6-all-clusters +infineon-p6-light infineon-p6-lock mbed-CY8CPROTO_062_4343W-all-clusters-release mbed-CY8CPROTO_062_4343W-light-release diff --git a/src/platform/P6/ConfigurationManagerImpl.cpp b/src/platform/P6/ConfigurationManagerImpl.cpp index 067ca9ab4f749b..ef408fec77decd 100644 --- a/src/platform/P6/ConfigurationManagerImpl.cpp +++ b/src/platform/P6/ConfigurationManagerImpl.cpp @@ -46,6 +46,28 @@ CHIP_ERROR ConfigurationManagerImpl::Init() { CHIP_ERROR err = CHIP_NO_ERROR; bool failSafeArmed; + uint32_t rebootCount; + + if (P6Config::ConfigValueExists(P6Config::kCounterKey_RebootCount)) + { + err = GetRebootCount(rebootCount); + SuccessOrExit(err); + + err = StoreRebootCount(rebootCount + 1); + SuccessOrExit(err); + } + else + { + // The first boot after factory reset of the Node. + err = StoreRebootCount(1); + SuccessOrExit(err); + } + + if (!P6Config::ConfigValueExists(P6Config::kCounterKey_TotalOperationalHours)) + { + err = StoreTotalOperationalHours(0); + SuccessOrExit(err); + } // Initialize the generic implementation base class. err = Internal::GenericConfigurationManagerImpl::Init(); @@ -58,9 +80,30 @@ CHIP_ERROR ConfigurationManagerImpl::Init() InitiateFactoryReset(); } +exit: return err; } +CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) +{ + return ReadConfigValue(P6Config::kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreRebootCount(uint32_t rebootCount) +{ + return WriteConfigValue(P6Config::kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + return ReadConfigValue(P6Config::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return WriteConfigValue(P6Config::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/platform/P6/ConfigurationManagerImpl.h b/src/platform/P6/ConfigurationManagerImpl.h index 8aae8d9227f44c..8da0df2b060579 100644 --- a/src/platform/P6/ConfigurationManagerImpl.h +++ b/src/platform/P6/ConfigurationManagerImpl.h @@ -38,6 +38,10 @@ namespace DeviceLayer { class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImpl { public: + CHIP_ERROR GetRebootCount(uint32_t & rebootCount) override; + CHIP_ERROR StoreRebootCount(uint32_t rebootCount) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override; // This returns an instance of this class. static ConfigurationManagerImpl & GetDefaultInstance(); diff --git a/src/platform/P6/DiagnosticDataProviderImpl.cpp b/src/platform/P6/DiagnosticDataProviderImpl.cpp index 02593d420e2501..3187f917a11784 100644 --- a/src/platform/P6/DiagnosticDataProviderImpl.cpp +++ b/src/platform/P6/DiagnosticDataProviderImpl.cpp @@ -23,9 +23,12 @@ #include +#include "cyhal_system.h" +#include #include #include #include +#include namespace chip { namespace DeviceLayer { @@ -36,5 +39,509 @@ DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() return sInstance; } +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree) +{ + heap_info_t heap; + Internal::P6Utils::heap_usage(&heap); + currentHeapFree = static_cast(heap.HeapFree); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed) +{ + // Calculate the Heap used based on Total heap - Free heap + heap_info_t heap; + Internal::P6Utils::heap_usage(&heap); + currentHeapUsed = static_cast(heap.HeapUsed); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) +{ + heap_info_t heap; + Internal::P6Utils::heap_usage(&heap); + currentHeapHighWatermark = static_cast(heap.HeapMax); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) +{ + uint32_t count = 0; + + CHIP_ERROR err = ConfigurationMgr().GetRebootCount(count); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rebootCount = static_cast(count); + } + + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime) +{ + System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = PlatformMgrImpl().GetStartTime(); + + if (currentTime >= startTime) + { + upTime = std::chrono::duration_cast(currentTime - startTime).count(); + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + uint64_t upTime = 0; + + if (GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalHours = 0; + if (ConfigurationMgr().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR) + { + /* uptime is terms of seconds and dividing it by 3600 to calculate + * totalOperationalHours in hours. + */ + VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + totalOperationalHours = totalHours + static_cast(upTime / 3600); + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(uint8_t & bootReason) +{ + cyhal_reset_reason_t reset_reason = cyhal_system_get_reset_reason(); + if (reset_reason == CYHAL_SYSTEM_RESET_NONE) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_POWER_ON_REBOOT; + } + else if (reset_reason == CYHAL_SYSTEM_RESET_WDT) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_WATCHDOG_RESET; + } + else if (reset_reason == CYHAL_SYSTEM_RESET_SOFT) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_RESET; + } + else if (reset_reason == CYHAL_SYSTEM_RESET_HIB_WAKEUP) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_HARDWARE_WATCHDOG_RESET; + } + else + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; + } + return CHIP_NO_ERROR; +} + +void DiagnosticDataProviderImpl::UpdateoffPremiseService(bool ipv4service, bool ipv6service) +{ + /* Enable/Disable IPv4 Off Premise Services */ + mipv4_offpremise = ipv4service; + + /* Enable/Disable IPv6 Off Premise Services */ + mipv6_offpremise = ipv6service; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp) +{ + struct netif * net_interface; + CHIP_ERROR err = CHIP_NO_ERROR; + NetworkInterface * ifp = new NetworkInterface(); + net_interface = cy_lwip_get_interface(CY_LWIP_STA_NW_INTERFACE); + if (net_interface) + { + /* Update Network Interface list */ + ifp->name = CharSpan(net_interface->name, strlen(net_interface->name)); + ifp->fabricConnected = net_interface->flags & NETIF_FLAG_LINK_UP; + ifp->type = EMBER_ZCL_INTERFACE_TYPE_WI_FI; + ifp->offPremiseServicesReachableIPv4 = mipv4_offpremise; + ifp->offPremiseServicesReachableIPv6 = mipv6_offpremise; + ifp->hardwareAddress = ByteSpan(net_interface->hwaddr, net_interface->hwaddr_len); + } + *netifpp = ifp; + + return err; +} + +void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) +{ + while (netifp) + { + NetworkInterface * del = netifp; + netifp = netifp->Next; + delete del; + } +} + +/* Wi-Fi Diagnostics Cluster Support */ + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBssId(ByteSpan & value) +{ + cy_wcm_associated_ap_info_t ap_info; + cy_rslt_t result = CY_RSLT_SUCCESS; + CHIP_ERROR err = CHIP_NO_ERROR; + ChipLogError(DeviceLayer, "cy_wcm_get_associated_ap_info\r\n"); + result = cy_wcm_get_associated_ap_info(&ap_info); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_associated_ap_info failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + memcpy(mWiFiMacAddress, ap_info.BSSID, CY_WCM_MAC_ADDR_LEN); + value = ByteSpan(mWiFiMacAddress, CY_WCM_MAC_ADDR_LEN); + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiSecurityType(uint8_t & securityType) +{ + cy_wcm_associated_ap_info_t ap_info; + cy_rslt_t result = CY_RSLT_SUCCESS; + CHIP_ERROR err = CHIP_NO_ERROR; + + result = cy_wcm_get_associated_ap_info(&ap_info); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_associated_ap_info failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + if (ap_info.security == CY_WCM_SECURITY_OPEN) + { + securityType = EMBER_ZCL_SECURITY_TYPE_NONE; + } + else if (ap_info.security & WPA3_SECURITY) + { + securityType = EMBER_ZCL_SECURITY_TYPE_WPA3; + } + else if (ap_info.security & WPA2_SECURITY) + { + securityType = EMBER_ZCL_SECURITY_TYPE_WPA2; + } + else if (ap_info.security & WPA_SECURITY) + { + securityType = EMBER_ZCL_SECURITY_TYPE_WPA; + } + else if (ap_info.security & WEP_ENABLED) + { + securityType = EMBER_ZCL_SECURITY_TYPE_WEP; + } + else + { + securityType = EMBER_ZCL_SECURITY_TYPE_UNSPECIFIED; + } + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiVersion(uint8_t & wiFiVersion) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + wl_bss_info_t bss_info; + whd_security_t security; + cy_rslt_t result = CY_RSLT_SUCCESS; + + if (whd_wifi_get_ap_info(whd_ifs[CY_WCM_INTERFACE_TYPE_STA], &bss_info, &security) != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "whd_wifi_get_ap_info failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + /* VHT Capable bit variable is not defined in whd and has to use the reserved bit */ + if (bss_info.reserved[0]) + { + wiFiVersion = EMBER_ZCL_WI_FI_VERSION_TYPE_802__11AC; + } + /* HT Capable */ + else if (bss_info.n_cap) + { + wiFiVersion = EMBER_ZCL_WI_FI_VERSION_TYPE_802__11N; + } + /* 11g Capable */ + else + { + wiFiVersion = EMBER_ZCL_WI_FI_VERSION_TYPE_802__11G; + } + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiChannelNumber(uint16_t & channelNumber) +{ + cy_wcm_associated_ap_info_t ap_info; + cy_rslt_t result = CY_RSLT_SUCCESS; + CHIP_ERROR err = CHIP_NO_ERROR; + + result = cy_wcm_get_associated_ap_info(&ap_info); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_associated_ap_info failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + channelNumber = ap_info.channel; + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiRssi(int8_t & rssi) +{ + cy_wcm_associated_ap_info_t ap_info; + cy_rslt_t result = CY_RSLT_SUCCESS; + CHIP_ERROR err = CHIP_NO_ERROR; + + result = cy_wcm_get_associated_ap_info(&ap_info); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_associated_ap_info failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + rssi = ap_info.signal_strength; + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBeaconRxCount(uint32_t & beaconRxCount) +{ + uint64_t count; + ReturnErrorOnFailure(WiFiCounters(WiFiStatsCountType::kWiFiBeaconRxCount, count)); + + count -= mBeaconRxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + beaconRxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBeaconLostCount(uint32_t & beaconLostCount) +{ + uint64_t count; + ReturnErrorOnFailure(WiFiCounters(WiFiStatsCountType::kWiFiBeaconLostCount, count)); + + count -= mBeaconLostCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + beaconLostCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) +{ + cy_rslt_t result = CY_RSLT_SUCCESS; + cy_wcm_wlan_statistics_t stats; + CHIP_ERROR err = CHIP_NO_ERROR; + uint64_t count; + + result = cy_wcm_get_wlan_statistics(CY_WCM_INTERFACE_TYPE_STA, &stats); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_wlan_statistics failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + count = stats.tx_bitrate * PHYRATE_KPBS_BYTES_PER_SEC; + currentMaxRate = static_cast(count); + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) +{ + uint64_t count; + ReturnErrorOnFailure(WiFiCounters(WiFiStatsCountType::kWiFiMulticastPacketRxCount, count)); + + count -= mPacketMulticastRxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + packetMulticastRxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) +{ + uint64_t count; + ReturnErrorOnFailure(WiFiCounters(WiFiStatsCountType::kWiFiMulticastPacketTxCount, count)); + + count -= mPacketMulticastTxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + packetMulticastTxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) +{ + cy_rslt_t result = CY_RSLT_SUCCESS; + cy_wcm_wlan_statistics_t stats; + CHIP_ERROR err = CHIP_NO_ERROR; + uint64_t count; + + result = cy_wcm_get_wlan_statistics(CY_WCM_INTERFACE_TYPE_STA, &stats); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_wlan_statistics failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + count = stats.rx_packets; + count -= mPacketUnicastRxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetUnicastRxCount = static_cast(count); + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) +{ + cy_rslt_t result = CY_RSLT_SUCCESS; + cy_wcm_wlan_statistics_t stats; + CHIP_ERROR err = CHIP_NO_ERROR; + uint64_t count; + + result = cy_wcm_get_wlan_statistics(CY_WCM_INTERFACE_TYPE_STA, &stats); + if (result != CY_RSLT_SUCCESS) + { + ChipLogError(DeviceLayer, "cy_wcm_get_wlan_statistics failed: %d", (int) result); + SuccessOrExit(CHIP_ERROR_INTERNAL); + } + + count = stats.tx_packets; + count -= mPacketUnicastTxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetUnicastTxCount = static_cast(count); + +exit: + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiOverrunCount(uint64_t & overrunCount) +{ + uint64_t count; + ReturnErrorOnFailure(WiFiCounters(WiFiStatsCountType::kWiFiOverrunCount, count)); + + count -= mOverrunCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + overrunCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::ResetWiFiNetworkDiagnosticsCounts() +{ + uint64_t count; + return WiFiCounters(WiFiStatsCountType::kWiFiResetCount, count); +} + +void DiagnosticDataProviderImpl::ReadCounters(WiFiStatsCountType Counttype, uint64_t & count, wl_cnt_ver_30_t * cnt, + wl_cnt_ge40mcst_v1_t * cnt_ge40) +{ + if ((!cnt) || (!cnt_ge40)) + { + ChipLogError(DeviceLayer, "ReadCounters failed due to NULL Pointers passed"); + return; + } + /* Populate count based in the Counttype */ + switch (Counttype) + { + case WiFiStatsCountType::kWiFiUnicastPacketRxCount: + count = cnt->rxfrag; + break; + case WiFiStatsCountType::kWiFiUnicastPacketTxCount: + count = cnt->txfrag; + break; + case WiFiStatsCountType::kWiFiMulticastPacketRxCount: + count = cnt->rxmulti; + break; + case WiFiStatsCountType::kWiFiMulticastPacketTxCount: + count = cnt->txmulti; + break; + case WiFiStatsCountType::kWiFiOverrunCount: + count = cnt->txnobuf + cnt->rxnobuf; + break; + case WiFiStatsCountType::kWiFiBeaconLostCount: + count = cnt_ge40->missbcn_dbg; + break; + case WiFiStatsCountType::kWiFiBeaconRxCount: + count = cnt_ge40->rxbeaconmbss; + break; + /* Update below variables during reset counts command so that next count read will be + * starting from these values. + */ + case WiFiStatsCountType::kWiFiResetCount: + mBeaconRxCount = cnt_ge40->rxbeaconmbss; + mBeaconLostCount = cnt_ge40->missbcn_dbg; + mPacketMulticastRxCount = cnt->rxmulti; + mPacketMulticastTxCount = cnt->txmulti; + mPacketUnicastRxCount = cnt->rxfrag; + mPacketUnicastTxCount = cnt->txfrag; + mOverrunCount = cnt->txnobuf + cnt->rxnobuf; + break; + default: + ChipLogError(DeviceLayer, "ReadCounters type not handled : %d", (int) Counttype); + break; + } +} +void DiagnosticDataProviderImpl::xtlv_buffer_parsing(const uint8_t * tlv_buf, uint16_t buflen, WiFiStatsCountType Counttype, + uint64_t & count) +{ + wl_cnt_ver_30_t cnt; + wl_cnt_ge40mcst_v1_t cnt_ge40; + + /* parse the tlv buffer and populate the cnt and cnt_ge40 buffer with the counter values */ + Internal::P6Utils::unpack_xtlv_buf(tlv_buf, buflen, &cnt, &cnt_ge40); + + /* Read the counter based on the Counttype passed */ + ReadCounters(Counttype, count, &cnt, &cnt_ge40); + return; +} + +CHIP_ERROR DiagnosticDataProviderImpl::WiFiCounters(WiFiStatsCountType type, uint64_t & count) +{ + whd_buffer_t buffer; + whd_buffer_t response; + wl_cnt_info_t * wl_cnt_info = NULL; + CHIP_ERROR err = CHIP_NO_ERROR; + + /* Read wl counters iovar using WHD APIs */ + whd_cdc_get_iovar_buffer(whd_ifs[CY_WCM_INTERFACE_TYPE_STA]->whd_driver, &buffer, WLC_IOCTL_MEDLEN, IOVAR_STR_COUNTERS); + whd_cdc_send_iovar(whd_ifs[CY_WCM_INTERFACE_TYPE_STA], CDC_GET, buffer, &response); + wl_cnt_info = + (wl_cnt_info_t *) whd_buffer_get_current_piece_data_pointer(whd_ifs[CY_WCM_INTERFACE_TYPE_STA]->whd_driver, response); + + /* Parse the buffer only for Counter Version 30 */ + if (wl_cnt_info->version == WL_CNT_VER_30) + { + /* 43012 board - Process xtlv buffer data to get statistics */ + uint8_t * cntdata; + cntdata = (uint8_t *) malloc(wl_cnt_info->datalen); + + CHK_CNTBUF_DATALEN(wl_cnt_info, WLC_IOCTL_MEDLEN); + if (cntdata == NULL) + { + return CHIP_ERROR_INTERNAL; + } + /* Allocate the memory for buffer */ + memcpy(cntdata, wl_cnt_info->data, wl_cnt_info->datalen); + + /* parse the xtlv wl counters data */ + xtlv_buffer_parsing(cntdata, wl_cnt_info->datalen, type, count); + + /* Free the memory */ + free(cntdata); + } + return err; +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/P6/DiagnosticDataProviderImpl.h b/src/platform/P6/DiagnosticDataProviderImpl.h index 731f445fec8671..b15456ebc8351b 100644 --- a/src/platform/P6/DiagnosticDataProviderImpl.h +++ b/src/platform/P6/DiagnosticDataProviderImpl.h @@ -22,7 +22,34 @@ #pragma once +#include + +#include "whd.h" +#include "whd_buffer_api.h" +#include "whd_network_types.h" +#include "whd_wifi_api.h" +#include "whd_wlioctl.h" +#include #include +#include + +#define PHYRATE_KPBS_BYTES_PER_SEC 125 + +/* WiFi Counters */ +enum class WiFiStatsCountType +{ + kWiFiBeaconLostCount, + kWiFiBeaconRxCount, + kWiFiUnicastPacketRxCount, + kWiFiUnicastPacketTxCount, + kWiFiMulticastPacketRxCount, + kWiFiMulticastPacketTxCount, + kWiFiOverrunCount, + kWiFiResetCount +}; + +#define MAX_WHD_INTERFACE (2) +extern whd_interface_t whd_ifs[MAX_WHD_INTERFACE]; namespace chip { namespace DeviceLayer { @@ -34,6 +61,56 @@ class DiagnosticDataProviderImpl : public DiagnosticDataProvider { public: static DiagnosticDataProviderImpl & GetDefaultInstance(); + + // ===== Methods that implement the PlatformManager abstract interface. + + CHIP_ERROR GetCurrentHeapFree(uint64_t & currentHeapFree) override; + CHIP_ERROR GetCurrentHeapUsed(uint64_t & currentHeapUsed) override; + CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) override; + + CHIP_ERROR GetRebootCount(uint16_t & rebootCount) override; + CHIP_ERROR GetUpTime(uint64_t & upTime) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR GetBootReason(uint8_t & bootReason) override; + CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; + void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; + + CHIP_ERROR GetWiFiBssId(ByteSpan & BssId) override; + CHIP_ERROR GetWiFiSecurityType(uint8_t & securityType) override; + CHIP_ERROR GetWiFiVersion(uint8_t & wifiVersion) override; + CHIP_ERROR GetWiFiChannelNumber(uint16_t & channelNumber) override; + CHIP_ERROR GetWiFiRssi(int8_t & rssi) override; + CHIP_ERROR GetWiFiBeaconRxCount(uint32_t & beaconRxCount) override; + CHIP_ERROR GetWiFiBeaconLostCount(uint32_t & beaconLostCount) override; + CHIP_ERROR GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) override; + CHIP_ERROR GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) override; + CHIP_ERROR GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) override; + CHIP_ERROR GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) override; + CHIP_ERROR GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) override; + CHIP_ERROR GetWiFiOverrunCount(uint64_t & overrunCount) override; + CHIP_ERROR ResetWiFiNetworkDiagnosticsCounts() override; + CHIP_ERROR WiFiCounters(WiFiStatsCountType type, uint64_t & count); + void xtlv_buffer_parsing(const uint8_t * tlv_buf, uint16_t buflen, WiFiStatsCountType Counttype, uint64_t & count); + void ReadCounters(WiFiStatsCountType Counttype, uint64_t & count, wl_cnt_ver_30_t * cnt, wl_cnt_ge40mcst_v1_t * cnt_ge40); + /* Function to update ipv4 and ipv6 off premise service capability bit */ + void UpdateoffPremiseService(bool ipv4service, bool ipv6service); + /* These variables will be set to 0 during start up and will be updated when reset-counts + * zcl command is received. + * These are considered as base for below attributes of WiFi Diagnostics Cluster: + * BeaconLostCount, BeaconRxCount, PacketMulticastRxCount, PacketMulticastTxCount, + * PacketUnicastRxCount, PacketUnicastTxCount, OverrunCount. + * Each attributes read will be difference of WLAN counters minus equivalent variables below. + */ + uint32_t mBeaconRxCount = 0; + uint32_t mBeaconLostCount = 0; + uint32_t mPacketMulticastRxCount = 0; + uint32_t mPacketMulticastTxCount = 0; + uint32_t mPacketUnicastRxCount = 0; + uint32_t mPacketUnicastTxCount = 0; + uint64_t mOverrunCount = 0; + uint8_t mWiFiMacAddress[CY_WCM_MAC_ADDR_LEN]; + bool mipv4_offpremise = false; + bool mipv6_offpremise = false; }; } // namespace DeviceLayer diff --git a/src/platform/P6/KeyValueStoreManagerImpl.cpp b/src/platform/P6/KeyValueStoreManagerImpl.cpp index 13b09abc32b4d3..2cbda30f38dd7f 100644 --- a/src/platform/P6/KeyValueStoreManagerImpl.cpp +++ b/src/platform/P6/KeyValueStoreManagerImpl.cpp @@ -34,10 +34,12 @@ namespace PersistedStorage { KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; -KeyValueStoreManagerImpl::KeyValueStoreManagerImpl() +CHIP_ERROR KeyValueStoreManagerImpl::Init() { cy_rslt_t result = mtb_key_value_store_init(&kvstore_obj); init_success = (CY_RSLT_SUCCESS == result) ? true : false; + + return ConvertCyResultToChip(result); } CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, diff --git a/src/platform/P6/KeyValueStoreManagerImpl.h b/src/platform/P6/KeyValueStoreManagerImpl.h index fb8b62c735fc4d..29515f28218c67 100644 --- a/src/platform/P6/KeyValueStoreManagerImpl.h +++ b/src/platform/P6/KeyValueStoreManagerImpl.h @@ -37,7 +37,7 @@ class KeyValueStoreManagerImpl final : public KeyValueStoreManager friend class KeyValueStoreManager; public: - KeyValueStoreManagerImpl(); + CHIP_ERROR Init(); CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) const; CHIP_ERROR _Delete(const char * key); CHIP_ERROR _Put(const char * key, const void * value, size_t value_size); diff --git a/src/platform/P6/P6Config.cpp b/src/platform/P6/P6Config.cpp index 51665960ee91d3..71194b6ac4011f 100644 --- a/src/platform/P6/P6Config.cpp +++ b/src/platform/P6/P6Config.cpp @@ -71,6 +71,11 @@ const P6Config::Key P6Config::kConfigKey_LastUsedEpochKeyId = { kConfigNamespace const P6Config::Key P6Config::kConfigKey_FailSafeArmed = { kConfigNamespace_ChipConfig, "fail-safe-armed" }; const P6Config::Key P6Config::kConfigKey_WiFiStationSecType = { kConfigNamespace_ChipConfig, "sta-sec-type" }; +// Keys stored in the Chip-counters namespace +const P6Config::Key P6Config::kCounterKey_RebootCount = { kConfigNamespace_ChipCounters, "reboot-count" }; +const P6Config::Key P6Config::kCounterKey_UpTime = { kConfigNamespace_ChipCounters, "up-time" }; +const P6Config::Key P6Config::kCounterKey_TotalOperationalHours = { kConfigNamespace_ChipCounters, "total-hours" }; + // Prefix used for keys that contain Chip group encryption keys. const char P6Config::kGroupKeyNamePrefix[] = "gk-"; diff --git a/src/platform/P6/P6Config.h b/src/platform/P6/P6Config.h index 280a6d7217d2f7..7acfb5e13a5f07 100644 --- a/src/platform/P6/P6Config.h +++ b/src/platform/P6/P6Config.h @@ -75,6 +75,9 @@ class P6Config static const Key kConfigKey_RegulatoryLocation; static const Key kConfigKey_CountryCode; static const Key kConfigKey_Breadcrumb; + static const Key kCounterKey_RebootCount; + static const Key kCounterKey_UpTime; + static const Key kCounterKey_TotalOperationalHours; static const char kGroupKeyNamePrefix[]; diff --git a/src/platform/P6/P6Utils.cpp b/src/platform/P6/P6Utils.cpp index 578c47b12be065..3e08a3e6becddc 100644 --- a/src/platform/P6/P6Utils.cpp +++ b/src/platform/P6/P6Utils.cpp @@ -42,6 +42,7 @@ #include "lwip/sockets.h" #include "lwip/sys.h" #include "lwip/timeouts.h" +#include using namespace ::chip::DeviceLayer::Internal; using chip::DeviceLayer::Internal::DeviceNetworkInfo; @@ -675,3 +676,130 @@ CHIP_ERROR P6Utils::ping_init(void) } return err; } + +static int xtlv_hdr_size(uint16_t opts, const uint8_t ** data) +{ + int len = (int) OFFSETOF(xtlv_t, data); /* nominal */ + if (opts & XTLV_OPTION_LENU8) + { + --len; + } + if (opts & XTLV_OPTION_IDU8) + { + --len; + } + return len; +} + +static int xtlv_size_for_data(int dlen, uint16_t opts, const uint8_t ** data) +{ + int hsz; + hsz = xtlv_hdr_size(opts, data); + return ((opts & XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4) : (dlen + hsz)); +} + +static int xtlv_len(const xtlv_t * elt, uint16_t opts) +{ + const uint8_t * lenp; + int len; + + lenp = (const uint8_t *) &elt->len; /* nominal */ + if (opts & XTLV_OPTION_IDU8) + { + --lenp; + } + if (opts & XTLV_OPTION_LENU8) + { + len = *lenp; + } + else + { + len = _LTOH16_UA(lenp); + } + return len; +} + +static int xtlv_id(const xtlv_t * elt, uint16_t opts) +{ + int id = 0; + if (opts & XTLV_OPTION_IDU8) + { + id = *(const uint8_t *) elt; + } + else + { + id = _LTOH16_UA((const uint8_t *) elt); + } + return id; +} + +static void xtlv_unpack_xtlv(const xtlv_t * xtlv, uint16_t * type, uint16_t * len, const uint8_t ** data, uint16_t opts) +{ + if (type) + { + *type = (uint16_t) xtlv_id(xtlv, opts); + } + if (len) + { + *len = (uint16_t) xtlv_len(xtlv, opts); + } + if (data) + { + *data = (const uint8_t *) xtlv + xtlv_hdr_size(opts, data); + } +} + +void P6Utils::unpack_xtlv_buf(const uint8_t * tlv_buf, uint16_t buflen, wl_cnt_ver_30_t * cnt, wl_cnt_ge40mcst_v1_t * cnt_ge40) +{ + uint16_t len; + uint16_t type; + int size; + const xtlv_t * ptlv; + int sbuflen = buflen; + const uint8_t * data; + int hdr_size; + hdr_size = xtlv_hdr_size(XTLV_OPTION_ALIGN32, &data); + while (sbuflen >= hdr_size) + { + ptlv = (const xtlv_t *) tlv_buf; + + xtlv_unpack_xtlv(ptlv, &type, &len, &data, XTLV_OPTION_ALIGN32); + size = xtlv_size_for_data(len, XTLV_OPTION_ALIGN32, &data); + + sbuflen -= size; + if (sbuflen < 0) /* check for buffer overrun */ + { + break; + } + if (type == 0x100) + { + memcpy(cnt, (wl_cnt_ver_30_t *) data, sizeof(wl_cnt_ver_30_t)); + } + if (type == 0x400) + { + memcpy(cnt_ge40, (wl_cnt_ge40mcst_v1_t *) data, sizeof(wl_cnt_ge40mcst_v1_t)); + } + tlv_buf += size; + } +} + +/* Get the Heap total size for P6 Linker file */ +uint32_t get_heap_total() +{ + extern uint8_t __HeapBase; /* Symbol exported by the linker. */ + extern uint8_t __HeapLimit; /* Symbol exported by the linker. */ + + uint8_t * heap_base = (uint8_t *) &__HeapBase; + uint8_t * heap_limit = (uint8_t *) &__HeapLimit; + return (uint32_t)(heap_limit - heap_base); +} + +/* Populate Heap info based on heap total size and Current Heap usage */ +void P6Utils::heap_usage(heap_info_t * heap) +{ + struct mallinfo mall_info = mallinfo(); + + heap->HeapMax = mall_info.arena; + heap->HeapUsed = mall_info.uordblks; + heap->HeapFree = get_heap_total() - mall_info.uordblks; +} diff --git a/src/platform/P6/P6Utils.h b/src/platform/P6/P6Utils.h index d7850735c53372..62afdabdc411ec 100644 --- a/src/platform/P6/P6Utils.h +++ b/src/platform/P6/P6Utils.h @@ -20,6 +20,7 @@ #pragma once #include "platform/internal/DeviceNetworkInfo.h" +#include "whd_wlioctl.h" #include #include @@ -63,6 +64,123 @@ typedef enum WIFI_IF_STA_AP = CY_WCM_INTERFACE_TYPE_AP_STA, } wifi_interface_t; +/** MACSTAT counters for ucode (corerev >= 40) */ +typedef struct +{ + /* MAC counters: 32-bit version of d11.h's macstat_t */ + uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, + * Control Management (includes retransmissions) + */ + uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ + uint32 txctsfrm; /**< number of CTS sent out by the MAC */ + uint32 txackfrm; /**< number of ACK frames sent out */ + uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */ + uint32 txbcnfrm; /**< beacons transmitted */ + uint32 txfunfl[6]; /**< per-fifo tx underflows */ + uint32 txampdu; /**< number of AMPDUs transmitted */ + uint32 txmpdu; /**< number of MPDUs transmitted */ + uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS + * or BCN) + */ + uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for + * driver enqueued frames + */ + uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ + uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ + uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ + uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ + uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ + uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ + uint32 rxbadplcp; /**< parity check of the PLCP header failed */ + uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ + uint32 rxstrt; /**< Number of received frames with a good PLCP + * (i.e. passing parity check) + */ + uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ + uint32 rxmgucastmbss; /**< number of received mgmt frames with good FCS and matching RA */ + uint32 rxctlucast; /**< number of received CNTRL frames with good FCS and matching RA */ + uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ + uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ + uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ + uint32 rxdtocast; /**< number of received DATA frames (good FCS and not matching RA) */ + uint32 rxmgocast; /**< number of received MGMT frames (good FCS and not matching RA) */ + uint32 rxctlocast; /**< number of received CNTRL frame (good FCS and not matching RA) */ + uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ + uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ + uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */ + uint32 rxmgmcast; /**< number of RX Management multicast frames received by the MAC */ + uint32 rxctlmcast; /**< number of RX Control multicast frames received by the MAC + * (unlikely to see these) + */ + uint32 rxbeaconmbss; /**< beacons received from member of BSS */ + uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from + * other BSS (WDS FRAME) + */ + uint32 rxbeaconobss; /**< beacons received from other BSS */ + uint32 rxrsptmout; /**< number of response timeouts for transmitted frames + * expecting a response + */ + uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ + uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ + uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ + uint32 rxf1ovfl; /**< number of receive fifo 1 overflows */ + uint32 rxhlovfl; /**< number of length / header fifo overflows */ + uint32 missbcn_dbg; /**< number of beacon missed to receive */ + uint32 pmqovfl; /**< number of PMQ overflows */ + uint32 rxcgprqfrm; /**< number of received Probe requests that made it into + * the PRQ fifo + */ + uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ + uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did + * not get ACK + */ + uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ + uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ + * fifo because a probe response could not be sent out within + * the time limit defined in M_PRS_MAXTIME + */ + uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */ + uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */ + uint32 txinrtstxop; /**< number of data frame transmissions during rts txop */ + uint32 rxback; /**< blockack rxcnt */ + uint32 txback; /**< blockack txcnt */ + uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ + uint32 rxdrop20s; /**< drop secondary cnt */ + uint32 rxtoolate; /**< receive too late */ + uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ + /* XXX: All counter variables have to be of uint32. */ +} wl_cnt_ge40mcst_v1_t; + +typedef struct xtlv +{ + uint16_t id; + uint16_t len; + uint8_t data[1]; +} xtlv_t; + +#define WL_CNT_VER_30 (30) + +/* XTLV Format parsing for wl counters support */ +#define XTLV_OPTION_ALIGN32 0x0001 /* 32bit alignment of type.len.data */ +#define XTLV_OPTION_IDU8 0x0002 /* shorter id */ +#define XTLV_OPTION_LENU8 0x0004 /* shorted length */ +#define OFFSETOF(type, member) ((uintptr_t) & ((type *) 0)->member) +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) + +#define CHK_CNTBUF_DATALEN(cntbuf, ioctl_buflen) \ + do \ + { \ + if (((wl_cnt_info_t *) cntbuf)->datalen + OFFSETOF(wl_cnt_info_t, data) > ioctl_buflen) \ + printf("%s: IOVAR buffer short!\n", __FUNCTION__); \ + } while (0) + +typedef struct heap_info +{ + size_t HeapMax; + size_t HeapUsed; + size_t HeapFree; +} heap_info_t; + namespace chip { namespace DeviceLayer { namespace Internal { @@ -98,6 +216,8 @@ class P6Utils const cy_wcm_passphrase_t * password, cy_wcm_security_t security = CY_WCM_SECURITY_OPEN); static CHIP_ERROR OnIPAddressAvailable(void); static CHIP_ERROR ping_init(void); + static void unpack_xtlv_buf(const uint8_t * tlv_buf, uint16_t buflen, wl_cnt_ver_30_t * cnt, wl_cnt_ge40mcst_v1_t * cnt_ge40); + static void heap_usage(heap_info_t * heap); }; } // namespace Internal diff --git a/src/platform/P6/PlatformManagerImpl.cpp b/src/platform/P6/PlatformManagerImpl.cpp index 24272b1dae6b89..0ff0ce3a29f6c1 100644 --- a/src/platform/P6/PlatformManagerImpl.cpp +++ b/src/platform/P6/PlatformManagerImpl.cpp @@ -50,6 +50,8 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) err = Internal::InitLwIPCoreLock(); SuccessOrExit(err); + mStartTime = System::SystemClock().GetMonotonicTimestamp(); + // Call _InitChipStack() on the generic implementation base class // to finish the initialization process. err = Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(); @@ -64,5 +66,30 @@ CHIP_ERROR PlatformManagerImpl::InitLwIPCoreLock(void) return Internal::InitLwIPCoreLock(); } +CHIP_ERROR PlatformManagerImpl::_Shutdown() +{ + uint64_t upTime = 0; + + if (GetDiagnosticDataProvider().GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalOperationalHours = 0; + + if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + static_cast(upTime / 3600)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + } + else + { + ChipLogError(DeviceLayer, "Failed to get current uptime since the Node’s last reboot"); + } + + return Internal::GenericPlatformManagerImpl_FreeRTOS::_Shutdown(); +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/P6/PlatformManagerImpl.h b/src/platform/P6/PlatformManagerImpl.h index 8f3559bd80b3d4..f7c56ac435097c 100644 --- a/src/platform/P6/PlatformManagerImpl.h +++ b/src/platform/P6/PlatformManagerImpl.h @@ -49,17 +49,21 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener // ===== Platform-specific members that may be accessed directly by the application. CHIP_ERROR InitLwIPCoreLock(void); + System::Clock::Timestamp GetStartTime() { return mStartTime; } private: // ===== Methods that implement the PlatformManager abstract interface. CHIP_ERROR _InitChipStack(void); + CHIP_ERROR _Shutdown(); // ===== Members for internal use by the following friends. friend PlatformManager & PlatformMgr(void); friend PlatformManagerImpl & PlatformMgrImpl(void); + System::Clock::Timestamp mStartTime = System::Clock::kZero; + static PlatformManagerImpl sInstance; };