diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 4efdd37d8c1388..d33643beb5ddce 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -1045,6 +1045,12 @@ menu "CHIP Device Layer" endmenu + config CHIP_ENABLE_BDX_LOG_TRANSFER + bool "Enable BDX log transfer" + default n + help + Enables the BDX protocol for diagnostics log transfer + menu "Matter OTA Image" config CHIP_OTA_IMAGE_BUILD diff --git a/examples/temperature-measurement-app/esp32/README.md b/examples/temperature-measurement-app/esp32/README.md index 567e302c6f8df8..18d07ff639b06a 100644 --- a/examples/temperature-measurement-app/esp32/README.md +++ b/examples/temperature-measurement-app/esp32/README.md @@ -24,6 +24,36 @@ Usage: ./out/debug/chip-tool temperaturemeasurement read measured-value 1 ``` +## Additional details + +This example demonstrates the utilization of the diagnostic logs cluster to send +diagnostic logs to the client. + +In this scenario, the [main/diagnostic_logs](main/diagnostic_logs) directory +contains three files: + +``` +main/diagnostic_logs +├── crash.log +├── end_user_support.log +└── network_diag.log +``` + +These files contain dummy data. + +#### To test the diagnostic logs cluster + +``` +# Commission the app +chip-tool pairing ble-wifi 1 SSID PASSPHRASE 20202021 3840 + +# Read end user support logs using response payload protocol +chip-tool diagnosticlogs retrieve-logs-request 0 0 1 0 + +# Read network diagnostic using BDX protocol +chip-tool diagnosticlogs retrieve-logs-request 1 0 1 0 --TransferFileDesignator network-diag.log +``` + ## Optimization Optimization related to WiFi, BLuetooth, Asserts etc are the part of this diff --git a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt index b48d05d8949b88..8953d34869b76a 100644 --- a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt +++ b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt @@ -82,7 +82,8 @@ endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + PRIV_REQUIRES ${PRIV_REQUIRES_LIST} + EMBED_FILES diagnostic_logs/end_user_support.log diagnostic_logs/network_diag.log diagnostic_logs/crash.log) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") chip_app_component_codegen("${CHIP_ROOT}/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter") diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp b/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp new file mode 100644 index 00000000000000..4bef0fbd86cc19 --- /dev/null +++ b/examples/temperature-measurement-app/esp32/main/diagnostic-logs-provider-delegate-impl.cpp @@ -0,0 +1,161 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * 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 + +using namespace chip; +using namespace chip::app::Clusters::DiagnosticLogs; + +LogProvider LogProvider::sInstance; + +namespace { +bool IsValidIntent(IntentEnum intent) +{ + return intent != IntentEnum::kUnknownEnumValue; +} + +// end_user_support.log, network_diag.log, and crash.log files are embedded in the firmware +extern const uint8_t endUserSupportLogStart[] asm("_binary_end_user_support_log_start"); +extern const uint8_t endUserSupportLogEnd[] asm("_binary_end_user_support_log_end"); + +extern const uint8_t networkDiagnosticLogStart[] asm("_binary_network_diag_log_start"); +extern const uint8_t networkDiagnosticLogEnd[] asm("_binary_network_diag_log_end"); + +extern const uint8_t crashLogStart[] asm("_binary_crash_log_start"); +extern const uint8_t crashLogEnd[] asm("_binary_crash_log_end"); +} // namespace + +LogProvider::~LogProvider() +{ + for (auto sessionSpan : mSessionSpanMap) + { + Platform::MemoryFree(sessionSpan.second); + } + mSessionSpanMap.clear(); +} + +CHIP_ERROR LogProvider::GetLogForIntent(IntentEnum intent, MutableByteSpan & outBuffer, Optional & outTimeStamp, + Optional & outTimeSinceBoot) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + LogSessionHandle sessionHandle = kInvalidLogSessionHandle; + + err = StartLogCollection(intent, sessionHandle, outTimeStamp, outTimeSinceBoot); + VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0)); + + bool unusedOutIsEndOfLog; + err = CollectLog(sessionHandle, outBuffer, unusedOutIsEndOfLog); + VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0)); + + err = EndLogCollection(sessionHandle); + VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0)); + + return CHIP_NO_ERROR; +} + +const uint8_t * LogProvider::GetDataStartForIntent(IntentEnum intent) +{ + switch (intent) + { + case IntentEnum::kEndUserSupport: + return &endUserSupportLogStart[0]; + case IntentEnum::kNetworkDiag: + return &networkDiagnosticLogStart[0]; + case IntentEnum::kCrashLogs: + return &crashLogStart[0]; + default: + return nullptr; + } +} + +size_t LogProvider::GetSizeForIntent(IntentEnum intent) +{ + switch (intent) + { + case IntentEnum::kEndUserSupport: + return static_cast(endUserSupportLogEnd - endUserSupportLogStart); + case IntentEnum::kNetworkDiag: + return static_cast(networkDiagnosticLogEnd - networkDiagnosticLogStart); + case IntentEnum::kCrashLogs: + return static_cast(crashLogEnd - crashLogStart); + default: + return 0; + } +} + +CHIP_ERROR LogProvider::StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional & outTimeStamp, + Optional & outTimeSinceBoot) +{ + VerifyOrReturnValue(IsValidIntent(intent), CHIP_ERROR_INVALID_ARGUMENT); + + const uint8_t * dataStart = GetDataStartForIntent(intent); + VerifyOrReturnError(dataStart, CHIP_ERROR_NOT_FOUND); + + size_t dataSize = GetSizeForIntent(intent); + VerifyOrReturnError(dataSize, CHIP_ERROR_NOT_FOUND); + + ByteSpan * span = reinterpret_cast(Platform::MemoryCalloc(1, sizeof(ByteSpan))); + VerifyOrReturnValue(span, CHIP_ERROR_NO_MEMORY); + + *span = ByteSpan(dataStart, dataSize); + + mLogSessionHandle++; + // If the session handle rolls over to UINT16_MAX which is invalid, reset to 0. + VerifyOrDo(mLogSessionHandle != kInvalidLogSessionHandle, mLogSessionHandle = 0); + + outHandle = mLogSessionHandle; + mSessionSpanMap[mLogSessionHandle] = span; + return CHIP_NO_ERROR; +} + +CHIP_ERROR LogProvider::EndLogCollection(LogSessionHandle sessionHandle) +{ + VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); + + ByteSpan * span = mSessionSpanMap[sessionHandle]; + mSessionSpanMap.erase(sessionHandle); + + Platform::MemoryFree(span); + return CHIP_NO_ERROR; +} + +CHIP_ERROR LogProvider::CollectLog(LogSessionHandle sessionHandle, MutableByteSpan & outBuffer, bool & outIsEndOfLog) +{ + VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT); + + ByteSpan * span = mSessionSpanMap[sessionHandle]; + auto dataSize = span->size(); + auto count = std::min(dataSize, outBuffer.size()); + + VerifyOrReturnError(CanCastTo(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0)); + + ReturnErrorOnFailure(CopySpanToMutableSpan(ByteSpan(span->data(), count), outBuffer)); + + outIsEndOfLog = dataSize == count; + + if (!outIsEndOfLog) + { + // reduce the span after reading count bytes + *span = span->SubSpan(count); + } + + return CHIP_NO_ERROR; +} diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log new file mode 100644 index 00000000000000..04089de8ce7afd --- /dev/null +++ b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/crash.log @@ -0,0 +1,21 @@ +W (5047Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled. + +Core 0 register dump: +PC : 0x4009579a PS : 0x00060c33 A0 : 0x800941e1 A1 : 0x3fff3630 +0x4009579a: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:195 + +A2 : 0x00000006 A3 : 0x00060c20 A4 : 0x00000000 A5 : 0x00060c23 +A6 : 0xb33fffff A7 : 0xb33fffff A8 : 0x800950f0 A9 : 0x3fff3600 +A10 : 0x00000001 A11 : 0x000000fe A12 : 0x00000000 A13 : 0x00000000 +A14 : 0x00000000 A15 : 0x00000000 SAR : 0x0000000a EXCCAUSE: 0x0000001c +EXCVADDR: 0x00000016 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff +0x4000c2e0: memcpy in ROM +0x4000c2f6: memcpy in ROM + +Backtrace: 0x40095797:0x3fff3630 0x400941de:0x3fff3650 0x40154b39:0x3fff3670 0x40154b53:0x3fff3690 0x4013e20d:0x3fff36b0 0x40094fa6:0x3fff36d0 +0x40095797: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:202 +0x400941de: vTaskDelete at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:1434 (discriminator 4) +0x40154b39: esp_nimble_disable at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:55 +0x40154b53: nimble_port_freertos_deinit at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:80 +0x4013e20d: chip::DeviceLayer::Internal::BLEManagerImpl::bleprph_host_task(void*) at /home/smart/projects/smp_matter/build/esp-idf/chip/../../../../../../../opt/espressif/esp-matter/connectedhomeip/connectedhomeip/config/esp32/third_party/connectedhomeip/src/platform/ESP32/nimble/BLEManagerImpl.cpp:864 +0x40094fa6: vPortTaskWrapper at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162 diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic_logs/end_user_support.log b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/end_user_support.log new file mode 100644 index 00000000000000..2844b97dab5988 --- /dev/null +++ b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/end_user_support.log @@ -0,0 +1,3 @@ +I (223374) chip[light]: Turning on the smart light. +I (233374) chip[light]: Setting smart light level to 78 %. +I (243374) chip[light]: Turning off the smart light. diff --git a/examples/temperature-measurement-app/esp32/main/diagnostic_logs/network_diag.log b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/network_diag.log new file mode 100644 index 00000000000000..2b945b9cf4f48d --- /dev/null +++ b/examples/temperature-measurement-app/esp32/main/diagnostic_logs/network_diag.log @@ -0,0 +1,4 @@ +I (223374) chip[ndiag]: Wi-Fi connection status: 1 +I (233374) chip[ndiag]: Wi-Fi RSSI: -67 dBm +I (243374) chip[ndiag]: Minimum ever Wi-Fi RSSI: -80 dBm +I (253374) chip[ndiag]: Wi-Fi disconnection count: 16 diff --git a/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h b/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h new file mode 100644 index 00000000000000..d47dccafa6079d --- /dev/null +++ b/examples/temperature-measurement-app/esp32/main/include/diagnostic-logs-provider-delegate-impl.h @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * 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 + +namespace chip { +namespace app { +namespace Clusters { +namespace DiagnosticLogs { + +/** + * The LogProvider class serves as the sole instance delegate for handling diagnostic logs. + * + * It implements the DiagnosticLogsProviderDelegate interface + */ + +class LogProvider : public DiagnosticLogsProviderDelegate +{ +public: + static inline LogProvider & GetInstance() { return sInstance; } + + /////////// DiagnosticLogsProviderDelegate Interface ///////// + CHIP_ERROR StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional & outTimeStamp, + Optional & outTimeSinceBoot) override; + CHIP_ERROR EndLogCollection(LogSessionHandle sessionHandle) override; + CHIP_ERROR CollectLog(LogSessionHandle sessionHandle, MutableByteSpan & outBuffer, bool & outIsEndOfLog) override; + size_t GetSizeForIntent(IntentEnum intent) override; + CHIP_ERROR GetLogForIntent(IntentEnum intent, MutableByteSpan & outBuffer, Optional & outTimeStamp, + Optional & outTimeSinceBoot) override; + +private: + static LogProvider sInstance; + LogProvider() = default; + ~LogProvider(); + + LogProvider(const LogProvider &) = delete; + LogProvider & operator=(const LogProvider &) = delete; + + // This tracks the ByteSpan for each session + std::map mSessionSpanMap; + + LogSessionHandle mLogSessionHandle = kInvalidLogSessionHandle; + + const uint8_t * GetDataStartForIntent(IntentEnum intent); +}; + +} // namespace DiagnosticLogs +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/temperature-measurement-app/esp32/main/main.cpp b/examples/temperature-measurement-app/esp32/main/main.cpp index cb9ba768412772..9f7a73011a19a8 100644 --- a/examples/temperature-measurement-app/esp32/main/main.cpp +++ b/examples/temperature-measurement-app/esp32/main/main.cpp @@ -24,11 +24,13 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "nvs_flash.h" +#include #include #include #include #include #include +#include #include #include @@ -127,3 +129,10 @@ extern "C" void app_main() chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer, reinterpret_cast(nullptr)); } + +using namespace chip::app::Clusters::DiagnosticLogs; +void emberAfDiagnosticLogsClusterInitCallback(chip::EndpointId endpoint) +{ + auto & logProvider = LogProvider::GetInstance(); + DiagnosticLogsServer::Instance().SetDiagnosticLogsProviderDelegate(endpoint, &logProvider); +} diff --git a/examples/temperature-measurement-app/esp32/sdkconfig.defaults b/examples/temperature-measurement-app/esp32/sdkconfig.defaults index 81070fbfddb449..6d3243cabfeb8c 100644 --- a/examples/temperature-measurement-app/esp32/sdkconfig.defaults +++ b/examples/temperature-measurement-app/esp32/sdkconfig.defaults @@ -96,3 +96,6 @@ CONFIG_MBEDTLS_HKDF_C=y # Increase LwIP IPv6 address number CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 + +# Enable the diagnostic logs transfer over BDX protocol +CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER=y diff --git a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter index 4ee09b5869aaa4..fbd355a0b36da2 100644 --- a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter +++ b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter @@ -1452,10 +1452,15 @@ endpoint 0 { } server cluster DiagnosticLogs { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; ram attribute featureMap default = 0; ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.zap b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.zap index 01453667d4538c..fde996ded8a2fb 100644 --- a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.zap +++ b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.zap @@ -1573,9 +1573,81 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, @@ -3225,5 +3297,6 @@ "endpointId": 1, "networkId": 0 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/src/platform/ESP32/CHIPPlatformConfig.h b/src/platform/ESP32/CHIPPlatformConfig.h index 245f908d434adf..c2aa892ac04b13 100644 --- a/src/platform/ESP32/CHIPPlatformConfig.h +++ b/src/platform/ESP32/CHIPPlatformConfig.h @@ -95,3 +95,7 @@ #endif // CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC #endif // CONFIG_ENABLE_ICD_SERVER + +#ifdef CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER +#define CHIP_CONFIG_ENABLE_BDX_LOG_TRANSFER 1 +#endif // CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER