Skip to content

Commit 4d89506

Browse files
[ESP32] Diagnostic logs provider delegate implementation in temperature-meausement-app (project-chip#31682)
* [ESP32] Config option to use the BDX for diagnostics log transfer * Enable mandatory bits for diagnostics log cluster in temperature-measurement-app zap file * [ESP32] Implement diagnostics logs provider delegate in temperature-measurement-app * Restyled by clang-format * Restyled by prettier-markdown * Disable bdx protocol by default and enable in sdkconfig.defaults and address review comments * Restyled by prettier-markdown --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 446088c commit 4d89506

File tree

13 files changed

+390
-2
lines changed

13 files changed

+390
-2
lines changed

config/esp32/components/chip/Kconfig

+6
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,12 @@ menu "CHIP Device Layer"
10451045

10461046
endmenu
10471047

1048+
config CHIP_ENABLE_BDX_LOG_TRANSFER
1049+
bool "Enable BDX log transfer"
1050+
default n
1051+
help
1052+
Enables the BDX protocol for diagnostics log transfer
1053+
10481054
menu "Matter OTA Image"
10491055

10501056
config CHIP_OTA_IMAGE_BUILD

examples/temperature-measurement-app/esp32/README.md

+30
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,36 @@ Usage:
2424
./out/debug/chip-tool temperaturemeasurement read measured-value <NODE ID> 1
2525
```
2626

27+
## Additional details
28+
29+
This example demonstrates the utilization of the diagnostic logs cluster to send
30+
diagnostic logs to the client.
31+
32+
In this scenario, the [main/diagnostic_logs](main/diagnostic_logs) directory
33+
contains three files:
34+
35+
```
36+
main/diagnostic_logs
37+
├── crash.log
38+
├── end_user_support.log
39+
└── network_diag.log
40+
```
41+
42+
These files contain dummy data.
43+
44+
#### To test the diagnostic logs cluster
45+
46+
```
47+
# Commission the app
48+
chip-tool pairing ble-wifi 1 SSID PASSPHRASE 20202021 3840
49+
50+
# Read end user support logs using response payload protocol
51+
chip-tool diagnosticlogs retrieve-logs-request 0 0 1 0
52+
53+
# Read network diagnostic using BDX protocol
54+
chip-tool diagnosticlogs retrieve-logs-request 1 0 1 0 --TransferFileDesignator network-diag.log
55+
```
56+
2757
## Optimization
2858

2959
Optimization related to WiFi, BLuetooth, Asserts etc are the part of this

examples/temperature-measurement-app/esp32/main/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ endif (CONFIG_ENABLE_PW_RPC)
8282

8383
idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST}
8484
SRC_DIRS ${SRC_DIRS_LIST}
85-
PRIV_REQUIRES ${PRIV_REQUIRES_LIST})
85+
PRIV_REQUIRES ${PRIV_REQUIRES_LIST}
86+
EMBED_FILES diagnostic_logs/end_user_support.log diagnostic_logs/network_diag.log diagnostic_logs/crash.log)
8687

8788
include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake")
8889
chip_app_component_codegen("${CHIP_ROOT}/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include <diagnostic-logs-provider-delegate-impl.h>
20+
#include <lib/support/SafeInt.h>
21+
22+
using namespace chip;
23+
using namespace chip::app::Clusters::DiagnosticLogs;
24+
25+
LogProvider LogProvider::sInstance;
26+
27+
namespace {
28+
bool IsValidIntent(IntentEnum intent)
29+
{
30+
return intent != IntentEnum::kUnknownEnumValue;
31+
}
32+
33+
// end_user_support.log, network_diag.log, and crash.log files are embedded in the firmware
34+
extern const uint8_t endUserSupportLogStart[] asm("_binary_end_user_support_log_start");
35+
extern const uint8_t endUserSupportLogEnd[] asm("_binary_end_user_support_log_end");
36+
37+
extern const uint8_t networkDiagnosticLogStart[] asm("_binary_network_diag_log_start");
38+
extern const uint8_t networkDiagnosticLogEnd[] asm("_binary_network_diag_log_end");
39+
40+
extern const uint8_t crashLogStart[] asm("_binary_crash_log_start");
41+
extern const uint8_t crashLogEnd[] asm("_binary_crash_log_end");
42+
} // namespace
43+
44+
LogProvider::~LogProvider()
45+
{
46+
for (auto sessionSpan : mSessionSpanMap)
47+
{
48+
Platform::MemoryFree(sessionSpan.second);
49+
}
50+
mSessionSpanMap.clear();
51+
}
52+
53+
CHIP_ERROR LogProvider::GetLogForIntent(IntentEnum intent, MutableByteSpan & outBuffer, Optional<uint64_t> & outTimeStamp,
54+
Optional<uint64_t> & outTimeSinceBoot)
55+
{
56+
CHIP_ERROR err = CHIP_NO_ERROR;
57+
LogSessionHandle sessionHandle = kInvalidLogSessionHandle;
58+
59+
err = StartLogCollection(intent, sessionHandle, outTimeStamp, outTimeSinceBoot);
60+
VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0));
61+
62+
bool unusedOutIsEndOfLog;
63+
err = CollectLog(sessionHandle, outBuffer, unusedOutIsEndOfLog);
64+
VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0));
65+
66+
err = EndLogCollection(sessionHandle);
67+
VerifyOrReturnError(CHIP_NO_ERROR == err, err, outBuffer.reduce_size(0));
68+
69+
return CHIP_NO_ERROR;
70+
}
71+
72+
const uint8_t * LogProvider::GetDataStartForIntent(IntentEnum intent)
73+
{
74+
switch (intent)
75+
{
76+
case IntentEnum::kEndUserSupport:
77+
return &endUserSupportLogStart[0];
78+
case IntentEnum::kNetworkDiag:
79+
return &networkDiagnosticLogStart[0];
80+
case IntentEnum::kCrashLogs:
81+
return &crashLogStart[0];
82+
default:
83+
return nullptr;
84+
}
85+
}
86+
87+
size_t LogProvider::GetSizeForIntent(IntentEnum intent)
88+
{
89+
switch (intent)
90+
{
91+
case IntentEnum::kEndUserSupport:
92+
return static_cast<size_t>(endUserSupportLogEnd - endUserSupportLogStart);
93+
case IntentEnum::kNetworkDiag:
94+
return static_cast<size_t>(networkDiagnosticLogEnd - networkDiagnosticLogStart);
95+
case IntentEnum::kCrashLogs:
96+
return static_cast<size_t>(crashLogEnd - crashLogStart);
97+
default:
98+
return 0;
99+
}
100+
}
101+
102+
CHIP_ERROR LogProvider::StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional<uint64_t> & outTimeStamp,
103+
Optional<uint64_t> & outTimeSinceBoot)
104+
{
105+
VerifyOrReturnValue(IsValidIntent(intent), CHIP_ERROR_INVALID_ARGUMENT);
106+
107+
const uint8_t * dataStart = GetDataStartForIntent(intent);
108+
VerifyOrReturnError(dataStart, CHIP_ERROR_NOT_FOUND);
109+
110+
size_t dataSize = GetSizeForIntent(intent);
111+
VerifyOrReturnError(dataSize, CHIP_ERROR_NOT_FOUND);
112+
113+
ByteSpan * span = reinterpret_cast<ByteSpan *>(Platform::MemoryCalloc(1, sizeof(ByteSpan)));
114+
VerifyOrReturnValue(span, CHIP_ERROR_NO_MEMORY);
115+
116+
*span = ByteSpan(dataStart, dataSize);
117+
118+
mLogSessionHandle++;
119+
// If the session handle rolls over to UINT16_MAX which is invalid, reset to 0.
120+
VerifyOrDo(mLogSessionHandle != kInvalidLogSessionHandle, mLogSessionHandle = 0);
121+
122+
outHandle = mLogSessionHandle;
123+
mSessionSpanMap[mLogSessionHandle] = span;
124+
return CHIP_NO_ERROR;
125+
}
126+
127+
CHIP_ERROR LogProvider::EndLogCollection(LogSessionHandle sessionHandle)
128+
{
129+
VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT);
130+
VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT);
131+
132+
ByteSpan * span = mSessionSpanMap[sessionHandle];
133+
mSessionSpanMap.erase(sessionHandle);
134+
135+
Platform::MemoryFree(span);
136+
return CHIP_NO_ERROR;
137+
}
138+
139+
CHIP_ERROR LogProvider::CollectLog(LogSessionHandle sessionHandle, MutableByteSpan & outBuffer, bool & outIsEndOfLog)
140+
{
141+
VerifyOrReturnValue(sessionHandle != kInvalidLogSessionHandle, CHIP_ERROR_INVALID_ARGUMENT);
142+
VerifyOrReturnValue(mSessionSpanMap.count(sessionHandle), CHIP_ERROR_INVALID_ARGUMENT);
143+
144+
ByteSpan * span = mSessionSpanMap[sessionHandle];
145+
auto dataSize = span->size();
146+
auto count = std::min(dataSize, outBuffer.size());
147+
148+
VerifyOrReturnError(CanCastTo<off_t>(count), CHIP_ERROR_INVALID_ARGUMENT, outBuffer.reduce_size(0));
149+
150+
ReturnErrorOnFailure(CopySpanToMutableSpan(ByteSpan(span->data(), count), outBuffer));
151+
152+
outIsEndOfLog = dataSize == count;
153+
154+
if (!outIsEndOfLog)
155+
{
156+
// reduce the span after reading count bytes
157+
*span = span->SubSpan(count);
158+
}
159+
160+
return CHIP_NO_ERROR;
161+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
W (5047Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
2+
3+
Core 0 register dump:
4+
PC : 0x4009579a PS : 0x00060c33 A0 : 0x800941e1 A1 : 0x3fff3630
5+
0x4009579a: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:195
6+
7+
A2 : 0x00000006 A3 : 0x00060c20 A4 : 0x00000000 A5 : 0x00060c23
8+
A6 : 0xb33fffff A7 : 0xb33fffff A8 : 0x800950f0 A9 : 0x3fff3600
9+
A10 : 0x00000001 A11 : 0x000000fe A12 : 0x00000000 A13 : 0x00000000
10+
A14 : 0x00000000 A15 : 0x00000000 SAR : 0x0000000a EXCCAUSE: 0x0000001c
11+
EXCVADDR: 0x00000016 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
12+
0x4000c2e0: memcpy in ROM
13+
0x4000c2f6: memcpy in ROM
14+
15+
Backtrace: 0x40095797:0x3fff3630 0x400941de:0x3fff3650 0x40154b39:0x3fff3670 0x40154b53:0x3fff3690 0x4013e20d:0x3fff36b0 0x40094fa6:0x3fff36d0
16+
0x40095797: uxListRemove at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/list.c:202
17+
0x400941de: vTaskDelete at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:1434 (discriminator 4)
18+
0x40154b39: esp_nimble_disable at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:55
19+
0x40154b53: nimble_port_freertos_deinit at /opt/espressif/esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c:80
20+
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
21+
0x40094fa6: vPortTaskWrapper at /opt/espressif/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
I (223374) chip[light]: Turning on the smart light.
2+
I (233374) chip[light]: Setting smart light level to 78 %.
3+
I (243374) chip[light]: Turning off the smart light.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
I (223374) chip[ndiag]: Wi-Fi connection status: 1
2+
I (233374) chip[ndiag]: Wi-Fi RSSI: -67 dBm
3+
I (243374) chip[ndiag]: Minimum ever Wi-Fi RSSI: -80 dBm
4+
I (253374) chip[ndiag]: Wi-Fi disconnection count: 16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <app/clusters/diagnostic-logs-server/DiagnosticLogsProviderDelegate.h>
22+
#include <map>
23+
24+
namespace chip {
25+
namespace app {
26+
namespace Clusters {
27+
namespace DiagnosticLogs {
28+
29+
/**
30+
* The LogProvider class serves as the sole instance delegate for handling diagnostic logs.
31+
*
32+
* It implements the DiagnosticLogsProviderDelegate interface
33+
*/
34+
35+
class LogProvider : public DiagnosticLogsProviderDelegate
36+
{
37+
public:
38+
static inline LogProvider & GetInstance() { return sInstance; }
39+
40+
/////////// DiagnosticLogsProviderDelegate Interface /////////
41+
CHIP_ERROR StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional<uint64_t> & outTimeStamp,
42+
Optional<uint64_t> & outTimeSinceBoot) override;
43+
CHIP_ERROR EndLogCollection(LogSessionHandle sessionHandle) override;
44+
CHIP_ERROR CollectLog(LogSessionHandle sessionHandle, MutableByteSpan & outBuffer, bool & outIsEndOfLog) override;
45+
size_t GetSizeForIntent(IntentEnum intent) override;
46+
CHIP_ERROR GetLogForIntent(IntentEnum intent, MutableByteSpan & outBuffer, Optional<uint64_t> & outTimeStamp,
47+
Optional<uint64_t> & outTimeSinceBoot) override;
48+
49+
private:
50+
static LogProvider sInstance;
51+
LogProvider() = default;
52+
~LogProvider();
53+
54+
LogProvider(const LogProvider &) = delete;
55+
LogProvider & operator=(const LogProvider &) = delete;
56+
57+
// This tracks the ByteSpan for each session
58+
std::map<LogSessionHandle, ByteSpan *> mSessionSpanMap;
59+
60+
LogSessionHandle mLogSessionHandle = kInvalidLogSessionHandle;
61+
62+
const uint8_t * GetDataStartForIntent(IntentEnum intent);
63+
};
64+
65+
} // namespace DiagnosticLogs
66+
} // namespace Clusters
67+
} // namespace app
68+
} // namespace chip

examples/temperature-measurement-app/esp32/main/main.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
#include "freertos/FreeRTOS.h"
2525
#include "freertos/task.h"
2626
#include "nvs_flash.h"
27+
#include <app/clusters/diagnostic-logs-server/diagnostic-logs-server.h>
2728
#include <app/server/Server.h>
2829
#include <common/CHIPDeviceManager.h>
2930
#include <common/Esp32AppServer.h>
3031
#include <credentials/DeviceAttestationCredsProvider.h>
3132
#include <credentials/examples/DeviceAttestationCredsExample.h>
33+
#include <diagnostic-logs-provider-delegate-impl.h>
3234
#include <platform/ESP32/ESP32Utils.h>
3335

3436
#include <cmath>
@@ -127,3 +129,10 @@ extern "C" void app_main()
127129

128130
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer, reinterpret_cast<intptr_t>(nullptr));
129131
}
132+
133+
using namespace chip::app::Clusters::DiagnosticLogs;
134+
void emberAfDiagnosticLogsClusterInitCallback(chip::EndpointId endpoint)
135+
{
136+
auto & logProvider = LogProvider::GetInstance();
137+
DiagnosticLogsServer::Instance().SetDiagnosticLogsProviderDelegate(endpoint, &logProvider);
138+
}

examples/temperature-measurement-app/esp32/sdkconfig.defaults

+3
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,6 @@ CONFIG_MBEDTLS_HKDF_C=y
9696

9797
# Increase LwIP IPv6 address number
9898
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
99+
100+
# Enable the diagnostic logs transfer over BDX protocol
101+
CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER=y

examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter

+5
Original file line numberDiff line numberDiff line change
@@ -1452,10 +1452,15 @@ endpoint 0 {
14521452
}
14531453

14541454
server cluster DiagnosticLogs {
1455+
callback attribute generatedCommandList;
1456+
callback attribute acceptedCommandList;
1457+
callback attribute eventList;
1458+
callback attribute attributeList;
14551459
ram attribute featureMap default = 0;
14561460
ram attribute clusterRevision default = 1;
14571461

14581462
handle command RetrieveLogsRequest;
1463+
handle command RetrieveLogsResponse;
14591464
}
14601465

14611466
server cluster GeneralDiagnostics {

0 commit comments

Comments
 (0)