Skip to content

Commit

Permalink
[ESP32] Diagnostic logs provider delegate implementation in temperatu…
Browse files Browse the repository at this point in the history
…re-meausement-app (#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 <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Apr 8, 2024
1 parent 628d001 commit 9e2b6db
Show file tree
Hide file tree
Showing 13 changed files with 390 additions and 2 deletions.
6 changes: 6 additions & 0 deletions config/esp32/components/chip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions examples/temperature-measurement-app/esp32/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,36 @@ Usage:
./out/debug/chip-tool temperaturemeasurement read measured-value <NODE ID> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <diagnostic-logs-provider-delegate-impl.h>
#include <lib/support/SafeInt.h>

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<uint64_t> & outTimeStamp,
Optional<uint64_t> & 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<size_t>(endUserSupportLogEnd - endUserSupportLogStart);
case IntentEnum::kNetworkDiag:
return static_cast<size_t>(networkDiagnosticLogEnd - networkDiagnosticLogStart);
case IntentEnum::kCrashLogs:
return static_cast<size_t>(crashLogEnd - crashLogStart);
default:
return 0;
}
}

CHIP_ERROR LogProvider::StartLogCollection(IntentEnum intent, LogSessionHandle & outHandle, Optional<uint64_t> & outTimeStamp,
Optional<uint64_t> & 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<ByteSpan *>(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<off_t>(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;
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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 <app/clusters/diagnostic-logs-server/DiagnosticLogsProviderDelegate.h>
#include <map>

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<uint64_t> & outTimeStamp,
Optional<uint64_t> & 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<uint64_t> & outTimeStamp,
Optional<uint64_t> & 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<LogSessionHandle, ByteSpan *> mSessionSpanMap;

LogSessionHandle mLogSessionHandle = kInvalidLogSessionHandle;

const uint8_t * GetDataStartForIntent(IntentEnum intent);
};

} // namespace DiagnosticLogs
} // namespace Clusters
} // namespace app
} // namespace chip
9 changes: 9 additions & 0 deletions examples/temperature-measurement-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include <app/clusters/diagnostic-logs-server/diagnostic-logs-server.h>
#include <app/server/Server.h>
#include <common/CHIPDeviceManager.h>
#include <common/Esp32AppServer.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <diagnostic-logs-provider-delegate-impl.h>
#include <platform/ESP32/ESP32Utils.h>

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

chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer, reinterpret_cast<intptr_t>(nullptr));
}

using namespace chip::app::Clusters::DiagnosticLogs;
void emberAfDiagnosticLogsClusterInitCallback(chip::EndpointId endpoint)
{
auto & logProvider = LogProvider::GetInstance();
DiagnosticLogsServer::Instance().SetDiagnosticLogsProviderDelegate(endpoint, &logProvider);
}
3 changes: 3 additions & 0 deletions examples/temperature-measurement-app/esp32/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 9e2b6db

Please sign in to comment.