| /* |
| * |
| * 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 |
| * Provides an implementation of the DiagnosticDataProvider object |
| * for P6 platform. |
| */ |
| |
| #include <platform/internal/CHIPDeviceLayerInternal.h> |
| |
| #include "cyhal_system.h" |
| #include <cy_lwip.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <platform/DiagnosticDataProvider.h> |
| #include <platform/P6/DiagnosticDataProviderImpl.h> |
| #include <platform/P6/P6Utils.h> |
| |
| namespace chip { |
| namespace DeviceLayer { |
| |
| DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() |
| { |
| static DiagnosticDataProviderImpl sInstance; |
| return sInstance; |
| } |
| |
| CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree) |
| { |
| heap_info_t heap; |
| Internal::P6Utils::heap_usage(&heap); |
| currentHeapFree = static_cast<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint16_t>(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<System::Clock::Seconds64>(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<uint32_t>(upTime / 3600); |
| return CHIP_NO_ERROR; |
| } |
| } |
| |
| return CHIP_ERROR_INVALID_TIME; |
| } |
| |
| CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(BootReasonType & bootReason) |
| { |
| cyhal_reset_reason_t reset_reason = cyhal_system_get_reset_reason(); |
| if (reset_reason == CYHAL_SYSTEM_RESET_NONE) |
| { |
| bootReason = BootReasonType::kPowerOnReboot; |
| } |
| else if (reset_reason == CYHAL_SYSTEM_RESET_WDT) |
| { |
| bootReason = BootReasonType::kSoftwareWatchdogReset; |
| } |
| else if (reset_reason == CYHAL_SYSTEM_RESET_SOFT) |
| { |
| bootReason = BootReasonType::kSoftwareReset; |
| } |
| else if (reset_reason == CYHAL_SYSTEM_RESET_HIB_WAKEUP) |
| { |
| bootReason = BootReasonType::kHardwareWatchdogReset; |
| } |
| else |
| { |
| bootReason = BootReasonType::kUnspecified; |
| } |
| return CHIP_NO_ERROR; |
| } |
| |
| void DiagnosticDataProviderImpl::UpdateoffPremiseService(bool ipv4service, bool ipv6service) |
| { |
| /* Enable/Disable IPv4 Off Premise Services */ |
| mipv4_offpremise.SetNonNull(ipv4service); |
| |
| /* Enable/Disable IPv6 Off Premise Services */ |
| mipv6_offpremise.SetNonNull(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::fromCharString(net_interface->name); |
| ifp->isOperational = 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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 |