| /* |
| * |
| * Copyright (c) 2023 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. |
| */ |
| |
| /* |
| * This file implements the interface to the wifi sdk |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #if (SL_MATTER_GN_BUILD == 0) |
| #include "sl_matter_wifi_config.h" |
| #endif // SL_MATTER_GN_BUILD |
| |
| #include "FreeRTOS.h" |
| #include "WifiInterfaceAbstraction.h" |
| #include "ble_config.h" |
| #include "dhcp_client.h" |
| #include "event_groups.h" |
| #include "sl_board_configuration.h" |
| #include "sl_status.h" |
| #include "sl_wifi_device.h" |
| #include "task.h" |
| #include "wfx_host_events.h" |
| #include <app/icd/server/ICDServerConfig.h> |
| #include <inet/IPAddress.h> |
| #include <lib/support/CHIPMem.h> |
| #include <lib/support/CHIPMemString.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| |
| extern "C" { |
| #include "sl_net.h" |
| #include "sl_si91x_driver.h" |
| #include "sl_si91x_host_interface.h" |
| #include "sl_si91x_types.h" |
| #include "sl_wifi.h" |
| #include "sl_wifi_callback_framework.h" |
| #include "sl_wifi_constants.h" |
| #include "sl_wifi_types.h" |
| #include "wfx_host_events.h" |
| #if SL_MBEDTLS_USE_TINYCRYPT |
| #include "sl_si91x_constants.h" |
| #include "sl_si91x_trng.h" |
| #endif // SL_MBEDTLS_USE_TINYCRYPT |
| |
| #include <sl_net.h> |
| #include <sl_net_constants.h> |
| #include <sl_net_for_lwip.h> |
| #include <sl_net_wifi_types.h> |
| } |
| |
| #if SLI_SI91X_MCU_INTERFACE |
| #include "rsi_wisemcu_hardware_setup.h" |
| #endif // SLI_SI91X_MCU_INTERFACE |
| |
| #if (EXP_BOARD) |
| #include "rsi_bt_common_apis.h" |
| #endif |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE |
| #include "rsi_rom_power_save.h" |
| #include "sl_si91x_button_pin_config.h" |
| #include "sl_si91x_power_manager.h" |
| #endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE |
| |
| // Temmporary work-around for wifi-init failure in ACX modules with WiseConnect v3.3.3. This can be removed after integrating with |
| // WiseConnect v3.4.0 |
| #if (SL_SI91X_ACX_MODULE == 1) |
| #define REGION_CODE IGNORE_REGION |
| #else |
| #define REGION_CODE US |
| #endif |
| |
| WfxRsi_t wfx_rsi; |
| extern osSemaphoreId_t sl_rs_ble_init_sem; |
| |
| namespace { |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE |
| // TODO: should be removed once we are getting the press interrupt for button 0 with sleep |
| bool btn0_pressed = false; |
| #ifdef ENABLE_CHIP_SHELL |
| bool ps_requirement_added = false; |
| #endif // ENABLE_CHIP_SHELL |
| #endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE |
| |
| bool hasNotifiedWifiConnectivity = false; |
| bool hasNotifiedIPV6 = false; |
| #if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) |
| bool hasNotifiedIPV4 = false; |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ |
| |
| wfx_wifi_scan_ext_t temp_reset; |
| |
| osSemaphoreId_t sScanCompleteSemaphore; |
| osSemaphoreId_t sScanInProgressSemaphore; |
| osTimerId_t sDHCPTimer; |
| osMessageQueueId_t sWifiEventQueue = nullptr; |
| |
| sl_net_wifi_lwip_context_t wifi_client_context; |
| sl_wifi_security_t security = SL_WIFI_SECURITY_UNKNOWN; |
| |
| const sl_wifi_device_configuration_t config = { |
| .boot_option = LOAD_NWP_FW, |
| .mac_address = NULL, |
| .band = SL_SI91X_WIFI_BAND_2_4GHZ, |
| .region_code = REGION_CODE, |
| .boot_config = { .oper_mode = SL_SI91X_CLIENT_MODE, |
| .coex_mode = SL_SI91X_WLAN_BLE_MODE, |
| .feature_bit_map = |
| #ifdef SLI_SI91X_MCU_INTERFACE |
| (SL_SI91X_FEAT_SECURITY_OPEN | SL_SI91X_FEAT_WPS_DISABLE), |
| #else |
| (SL_SI91X_FEAT_SECURITY_OPEN | SL_SI91X_FEAT_AGGREGATION), |
| #endif |
| .tcp_ip_feature_bit_map = (SL_SI91X_TCP_IP_FEAT_DHCPV4_CLIENT | SL_SI91X_TCP_IP_FEAT_DNS_CLIENT | |
| SL_SI91X_TCP_IP_FEAT_SSL | SL_SI91X_TCP_IP_FEAT_BYPASS |
| #ifdef ipv6_FEATURE_REQUIRED |
| | SL_SI91X_TCP_IP_FEAT_DHCPV6_CLIENT | SL_SI91X_TCP_IP_FEAT_IPV6 |
| #endif |
| | SL_SI91X_TCP_IP_FEAT_ICMP | SL_SI91X_TCP_IP_FEAT_EXTENSION_VALID), |
| .custom_feature_bit_map = (SL_SI91X_CUSTOM_FEAT_EXTENTION_VALID | RSI_CUSTOM_FEATURE_BIT_MAP), |
| .ext_custom_feature_bit_map = (RSI_EXT_CUSTOM_FEATURE_BIT_MAP | (SL_SI91X_EXT_FEAT_BT_CUSTOM_FEAT_ENABLE) |
| #if (defined A2DP_POWER_SAVE_ENABLE) |
| | SL_SI91X_EXT_FEAT_XTAL_CLK_ENABLE(2) |
| #endif |
| ), |
| .bt_feature_bit_map = (RSI_BT_FEATURE_BITMAP |
| #if (RSI_BT_GATT_ON_CLASSIC) |
| | SL_SI91X_BT_ATT_OVER_CLASSIC_ACL /* to support att over classic acl link */ |
| #endif |
| ), |
| #ifdef RSI_PROCESS_MAX_RX_DATA |
| .ext_tcp_ip_feature_bit_map = |
| (RSI_EXT_TCPIP_FEATURE_BITMAP | SL_SI91X_CONFIG_FEAT_EXTENTION_VALID | SL_SI91X_EXT_TCP_MAX_RECV_LENGTH), |
| #else |
| .ext_tcp_ip_feature_bit_map = (RSI_EXT_TCPIP_FEATURE_BITMAP | SL_SI91X_CONFIG_FEAT_EXTENTION_VALID), |
| #endif |
| //! ENABLE_BLE_PROTOCOL in bt_feature_bit_map |
| .ble_feature_bit_map = |
| ((SL_SI91X_BLE_MAX_NBR_PERIPHERALS(RSI_BLE_MAX_NBR_PERIPHERALS) | |
| SL_SI91X_BLE_MAX_NBR_CENTRALS(RSI_BLE_MAX_NBR_CENTRALS) | |
| SL_SI91X_BLE_MAX_NBR_ATT_SERV(RSI_BLE_MAX_NBR_ATT_SERV) | |
| SL_SI91X_BLE_MAX_NBR_ATT_REC(RSI_BLE_MAX_NBR_ATT_REC)) | |
| SL_SI91X_FEAT_BLE_CUSTOM_FEAT_EXTENTION_VALID | SL_SI91X_BLE_PWR_INX(RSI_BLE_PWR_INX) | |
| SL_SI91X_BLE_PWR_SAVE_OPTIONS(RSI_BLE_PWR_SAVE_OPTIONS) | SL_SI91X_916_BLE_COMPATIBLE_FEAT_ENABLE |
| #if RSI_BLE_GATT_ASYNC_ENABLE |
| | SL_SI91X_BLE_GATT_ASYNC_ENABLE |
| #endif |
| ), |
| |
| .ble_ext_feature_bit_map = ((SL_SI91X_BLE_NUM_CONN_EVENTS(RSI_BLE_NUM_CONN_EVENTS) | |
| SL_SI91X_BLE_NUM_REC_BYTES(RSI_BLE_NUM_REC_BYTES)) |
| #if RSI_BLE_INDICATE_CONFIRMATION_FROM_HOST |
| | SL_SI91X_BLE_INDICATE_CONFIRMATION_FROM_HOST // indication response from app |
| #endif |
| #if RSI_BLE_MTU_EXCHANGE_FROM_HOST |
| | SL_SI91X_BLE_MTU_EXCHANGE_FROM_HOST // MTU Exchange request initiation from app |
| #endif |
| #if RSI_BLE_SET_SCAN_RESP_DATA_FROM_HOST |
| | (SL_SI91X_BLE_SET_SCAN_RESP_DATA_FROM_HOST) // Set SCAN Resp Data from app |
| #endif |
| #if RSI_BLE_DISABLE_CODED_PHY_FROM_HOST |
| | (SL_SI91X_BLE_DISABLE_CODED_PHY_FROM_HOST) // Disable Coded PHY from app |
| #endif |
| #if BLE_SIMPLE_GATT |
| | SL_SI91X_BLE_GATT_INIT |
| #endif |
| ), |
| .config_feature_bit_map = (SL_SI91X_FEAT_SLEEP_GPIO_SEL_BITMAP | RSI_CONFIG_FEATURE_BITMAP) } |
| }; |
| |
| constexpr int8_t kAdvScanThreshold = -40; |
| constexpr uint8_t kAdvRssiToleranceThreshold = 5; |
| constexpr uint8_t kAdvActiveScanDuration = 15; |
| constexpr uint8_t kAdvPassiveScanDuration = 20; |
| constexpr uint8_t kAdvMultiProbe = 1; |
| constexpr uint8_t kAdvScanPeriodicity = 10; |
| |
| // TODO: Confirm that this value works for size and timing |
| constexpr uint8_t kWfxQueueSize = 10; |
| |
| // TODO: Figure out why we actually need this, we are already handling failure and retries somewhere else. |
| constexpr uint16_t kWifiScanTimeoutTicks = 10000; |
| |
| void DHCPTimerEventHandler(void * arg) |
| { |
| WfxEvent_t event = { .eventType = WFX_EVT_DHCP_POLL }; |
| sl_matter_wifi_post_event(&event); |
| } |
| |
| void CancelDHCPTimer(void) |
| { |
| VerifyOrReturn(osTimerIsRunning(sDHCPTimer), ChipLogDetail(DeviceLayer, "CancelDHCPTimer: timer not running")); |
| VerifyOrReturn(osTimerStop(sDHCPTimer) == osOK, ChipLogError(DeviceLayer, "CancelDHCPTimer: failed to stop timer")); |
| } |
| |
| void StartDHCPTimer(uint32_t timeout) |
| { |
| // Cancel timer if already started |
| CancelDHCPTimer(); |
| |
| VerifyOrReturn(osTimerStart(sDHCPTimer, pdMS_TO_TICKS(timeout)) == osOK, |
| ChipLogError(DeviceLayer, "StartDHCPTimer: failed to start timer")); |
| } |
| |
| sl_status_t sl_wifi_siwx917_init(void) |
| { |
| sl_status_t status = SL_STATUS_OK; |
| |
| #ifdef SLI_SI91X_MCU_INTERFACE |
| // SoC Configurations |
| uint8_t xtal_enable = 1; |
| status = sl_si91x_m4_ta_secure_handshake(SL_SI91X_ENABLE_XTAL, 1, &xtal_enable, 0, nullptr); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_si91x_m4_ta_secure_handshake failed: 0x%lx", static_cast<uint32_t>(status))); |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER |
| #ifdef ENABLE_CHIP_SHELL |
| // While using the matter shell with a Low Power Build, GPIO 1 is used to check the UULP PIN 1 status |
| // since UART doesn't act as a wakeup source in the UULP mode. |
| |
| // Configuring the NPS GPIO 1 |
| RSI_NPSSGPIO_SetPinMux(RTE_UULP_GPIO_1_PIN, 0); |
| |
| // Configure the NPSS GPIO direction to input |
| RSI_NPSSGPIO_SetDir(RTE_UULP_GPIO_1_PIN, 1); |
| |
| // Enable the REN |
| RSI_NPSSGPIO_InputBufferEn(RTE_UULP_GPIO_1_PIN, 1); |
| #endif // ENABLE_CHIP_SHELL |
| #endif // CHIP_CONFIG_ENABLE_ICD_SERVER |
| |
| #else |
| // NCP Configurations |
| status = sl_matter_wifi_platform_init(); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_matter_wifi_platform_init failed: 0x%lx", static_cast<uint32_t>(status))); |
| #endif // SLI_SI91X_MCU_INTERFACE |
| |
| sl_wifi_firmware_version_t version = { 0 }; |
| status = sl_wifi_get_firmware_version(&version); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_wifi_get_firmware_version failed: 0x%lx", static_cast<uint32_t>(status))); |
| |
| ChipLogDetail(DeviceLayer, "Firmware version is: %x%x.%d.%d.%d.%d.%d.%d", version.chip_id, version.rom_id, version.major, |
| version.minor, version.security_version, version.patch_num, version.customer_id, version.build_num); |
| |
| status = sl_wifi_get_mac_address(SL_WIFI_CLIENT_INTERFACE, (sl_mac_address_t *) &wfx_rsi.sta_mac.octet[0]); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_wifi_get_mac_address failed: 0x%lx", static_cast<uint32_t>(status))); |
| |
| #ifdef SL_MBEDTLS_USE_TINYCRYPT |
| constexpr uint32_t trngKey[TRNG_KEY_SIZE] = { 0x16157E2B, 0xA6D2AE28, 0x8815F7AB, 0x3C4FCF09 }; |
| |
| // To check the Entropy of TRNG and verify TRNG functioning. |
| status = sl_si91x_trng_entropy(); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_si91x_trng_entropy failed: 0x%lx", static_cast<uint32_t>(status))); |
| |
| // Initiate and program the key required for TRNG hardware engine |
| status = sl_si91x_trng_program_key((uint32_t *) trngKey, TRNG_KEY_SIZE); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, |
| ChipLogError(DeviceLayer, "sl_si91x_trng_program_key failed: 0x%lx", static_cast<uint32_t>(status))); |
| #endif // SL_MBEDTLS_USE_TINYCRYPT |
| |
| wfx_rsi.dev_state |= WFX_RSI_ST_DEV_READY; |
| osSemaphoreRelease(sl_rs_ble_init_sem); |
| return status; |
| } |
| |
| // TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API |
| #ifndef EXP_BOARD |
| sl_status_t ScanCallback(sl_wifi_event_t event, sl_wifi_scan_result_t * scan_result, uint32_t result_length, void * arg) |
| { |
| sl_status_t status = SL_STATUS_OK; |
| if (SL_WIFI_CHECK_IF_EVENT_FAILED(event)) |
| { |
| ChipLogError(DeviceLayer, "Scan Netwrok Failed: 0x%lx", *reinterpret_cast<sl_status_t *>(status)); |
| #if WIFI_ENABLE_SECURITY_WPA3_TRANSITION |
| security = SL_WIFI_WPA3; |
| #else |
| security = SL_WIFI_WPA_WPA2_MIXED; |
| #endif /* WIFI_ENABLE_SECURITY_WPA3_TRANSITION */ |
| |
| status = SL_STATUS_FAIL; |
| } |
| else |
| { |
| security = static_cast<sl_wifi_security_t>(scan_result->scan_info[0].security_mode); |
| wfx_rsi.ap_chan = scan_result->scan_info[0].rf_channel; |
| memcpy(&wfx_rsi.ap_mac.octet, scan_result->scan_info[0].bssid, BSSID_LEN); |
| } |
| |
| osSemaphoreRelease(sScanCompleteSemaphore); |
| return status; |
| } |
| #endif |
| |
| sl_status_t InitiateScan() |
| { |
| sl_status_t status = SL_STATUS_OK; |
| |
| // TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API |
| #ifndef EXP_BOARD |
| sl_wifi_ssid_t ssid = { 0 }; |
| |
| // TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API |
| sl_wifi_scan_configuration_t wifi_scan_configuration = default_wifi_scan_configuration; |
| |
| ssid.length = wfx_rsi.sec.ssid_length; |
| |
| // TODO: workaround because the string management with the null termination is flawed |
| chip::Platform::CopyString((char *) &ssid.value[0], ssid.length + 1, wfx_rsi.sec.ssid); |
| sl_wifi_set_scan_callback(ScanCallback, NULL); |
| |
| osSemaphoreAcquire(sScanInProgressSemaphore, osWaitForever); |
| |
| // This is an odd success code? |
| status = sl_wifi_start_scan(SL_WIFI_CLIENT_2_4GHZ_INTERFACE, &ssid, &wifi_scan_configuration); |
| if (status == SL_STATUS_IN_PROGRESS) |
| { |
| osSemaphoreAcquire(sScanCompleteSemaphore, kWifiScanTimeoutTicks); |
| status = SL_STATUS_OK; |
| } |
| |
| osSemaphoreRelease(sScanInProgressSemaphore); |
| #endif |
| |
| return status; |
| } |
| |
| sl_status_t SetWifiConfigurations() |
| { |
| sl_status_t status = SL_STATUS_OK; |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER |
| // Setting the listen interval to 0 which will set it to DTIM interval |
| sl_wifi_listen_interval_t sleep_interval = { .listen_interval = 0 }; |
| status = sl_wifi_set_listen_interval(SL_WIFI_CLIENT_INTERFACE, sleep_interval); |
| VerifyOrReturnError(status == SL_STATUS_OK, status); |
| |
| sl_wifi_advanced_client_configuration_t client_config = { .max_retry_attempts = 5 }; |
| status = sl_wifi_set_advanced_client_configuration(SL_WIFI_CLIENT_INTERFACE, &client_config); |
| VerifyOrReturnError(status == SL_STATUS_OK, status); |
| #endif // CHIP_CONFIG_ENABLE_ICD_SERVER |
| |
| status = sl_net_set_credential(SL_NET_DEFAULT_WIFI_CLIENT_CREDENTIAL_ID, SL_NET_WIFI_PSK, &wfx_rsi.sec.passkey[0], |
| wfx_rsi.sec.passkey_length); |
| VerifyOrReturnError(status == SL_STATUS_OK, status); |
| |
| sl_net_wifi_client_profile_t profile = { |
| .config = { |
| .ssid = { |
| //static cast because the types dont match |
| .length = static_cast<uint8_t>(wfx_rsi.sec.ssid_length), |
| }, |
| .channel = { |
| .channel = SL_WIFI_AUTO_CHANNEL, |
| .band = SL_WIFI_AUTO_BAND, |
| .bandwidth = SL_WIFI_AUTO_BANDWIDTH |
| }, |
| .bssid = {{0}}, |
| .bss_type = SL_WIFI_BSS_TYPE_INFRASTRUCTURE, |
| .security = security, |
| .encryption = SL_WIFI_NO_ENCRYPTION, |
| .client_options = SL_WIFI_JOIN_WITH_SCAN, |
| .credential_id = SL_NET_DEFAULT_WIFI_CLIENT_CREDENTIAL_ID, |
| }, |
| .ip = { |
| .mode = SL_IP_MANAGEMENT_DHCP, |
| .type = SL_IPV6, |
| .host_name = NULL, |
| .ip = {{{0}}}, |
| } |
| }; |
| // TODO: memcpy for now since the types dont match |
| memcpy((char *) &profile.config.ssid.value, wfx_rsi.sec.ssid, wfx_rsi.sec.ssid_length); |
| |
| status = sl_net_set_profile((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE, SL_NET_DEFAULT_WIFI_CLIENT_PROFILE_ID, &profile); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, ChipLogError(DeviceLayer, "sl_net_set_profile Failed")); |
| |
| return status; |
| } |
| |
| sl_status_t JoinWifiNetwork(void) |
| { |
| VerifyOrReturnError(!(wfx_rsi.dev_state & (WFX_RSI_ST_STA_CONNECTING | WFX_RSI_ST_STA_CONNECTED)), SL_STATUS_IN_PROGRESS); |
| sl_status_t status = SL_STATUS_OK; |
| |
| // Start Join Network |
| wfx_rsi.dev_state |= WFX_RSI_ST_STA_CONNECTING; |
| |
| status = SetWifiConfigurations(); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, ChipLogError(DeviceLayer, "Failure to set the Wifi Configurations!")); |
| |
| status = sl_net_up((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE, SL_NET_DEFAULT_WIFI_CLIENT_PROFILE_ID); |
| |
| if (status == SL_STATUS_OK || status == SL_STATUS_IN_PROGRESS) |
| { |
| WfxEvent_t event; |
| event.eventType = WFX_EVT_STA_CONN; |
| sl_matter_wifi_post_event(&event); |
| return status; |
| } |
| |
| // failure only happens when the firmware returns an error |
| ChipLogError(DeviceLayer, "sl_wifi_connect failed: 0x%lx", static_cast<uint32_t>(status)); |
| VerifyOrReturnError((wfx_rsi.join_retries <= MAX_JOIN_RETRIES_COUNT), status); |
| |
| wfx_rsi.dev_state &= ~(WFX_RSI_ST_STA_CONNECTING | WFX_RSI_ST_STA_CONNECTED); |
| ChipLogProgress(DeviceLayer, "Connection retry attempt %d", wfx_rsi.join_retries); |
| wfx_retry_connection(++wfx_rsi.join_retries); |
| |
| WfxEvent_t event; |
| event.eventType = WFX_EVT_STA_START_JOIN; |
| sl_matter_wifi_post_event(&event); |
| |
| return status; |
| } |
| |
| } // namespace |
| |
| /****************************************************************** |
| * @fn int32_t wfx_rsi_get_ap_info(wfx_wifi_scan_result_t *ap) |
| * @brief |
| * Getting the AP details |
| * @param[in] ap: access point |
| * @return |
| * status |
| *********************************************************************/ |
| int32_t wfx_rsi_get_ap_info(wfx_wifi_scan_result_t * ap) |
| { |
| sl_status_t status = SL_STATUS_OK; |
| int32_t rssi = 0; |
| ap->ssid_length = wfx_rsi.sec.ssid_length; |
| ap->security = wfx_rsi.sec.security; |
| ap->chan = wfx_rsi.ap_chan; |
| chip::Platform::CopyString(ap->ssid, ap->ssid_length, wfx_rsi.sec.ssid); |
| memcpy(&ap->bssid[0], &wfx_rsi.ap_mac.octet[0], BSSID_LEN); |
| sl_wifi_get_signal_strength(SL_WIFI_CLIENT_INTERFACE, &rssi); |
| ap->rssi = rssi; |
| return status; |
| } |
| |
| /****************************************************************** |
| * @fn int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t *extra_info) |
| * @brief |
| * Getting the AP extra details |
| * @param[in] extra info: access point extra information |
| * @return |
| * status |
| *********************************************************************/ |
| int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t * extra_info) |
| { |
| sl_status_t status = SL_STATUS_OK; |
| sl_wifi_statistics_t test = { 0 }; |
| status = sl_wifi_get_statistics(SL_WIFI_CLIENT_INTERFACE, &test); |
| VERIFY_STATUS_AND_RETURN(status); |
| extra_info->beacon_lost_count = test.beacon_lost_count - temp_reset.beacon_lost_count; |
| extra_info->beacon_rx_count = test.beacon_rx_count - temp_reset.beacon_rx_count; |
| extra_info->mcast_rx_count = test.mcast_rx_count - temp_reset.mcast_rx_count; |
| extra_info->mcast_tx_count = test.mcast_tx_count - temp_reset.mcast_tx_count; |
| extra_info->ucast_rx_count = test.ucast_rx_count - temp_reset.ucast_rx_count; |
| extra_info->ucast_tx_count = test.ucast_tx_count - temp_reset.ucast_tx_count; |
| extra_info->overrun_count = test.overrun_count - temp_reset.overrun_count; |
| return status; |
| } |
| |
| /****************************************************************** |
| * @fn int32_t wfx_rsi_reset_count(void) |
| * @brief |
| * Getting the driver reset count |
| * @param[in] None |
| * @return |
| * status |
| *********************************************************************/ |
| int32_t wfx_rsi_reset_count(void) |
| { |
| sl_wifi_statistics_t test = { 0 }; |
| sl_status_t status = SL_STATUS_OK; |
| status = sl_wifi_get_statistics(SL_WIFI_CLIENT_INTERFACE, &test); |
| VERIFY_STATUS_AND_RETURN(status); |
| temp_reset.beacon_lost_count = test.beacon_lost_count; |
| temp_reset.beacon_rx_count = test.beacon_rx_count; |
| temp_reset.mcast_rx_count = test.mcast_rx_count; |
| temp_reset.mcast_tx_count = test.mcast_tx_count; |
| temp_reset.ucast_rx_count = test.ucast_rx_count; |
| temp_reset.ucast_tx_count = test.ucast_tx_count; |
| temp_reset.overrun_count = test.overrun_count; |
| return status; |
| } |
| |
| /****************************************************************** |
| * @fn sl_wifi_platform_disconnect(void) |
| * @brief |
| * Getting the driver disconnect status |
| * @param[in] None |
| * @return |
| * status |
| *********************************************************************/ |
| int32_t sl_wifi_platform_disconnect(void) |
| { |
| return sl_net_down((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE); |
| } |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER |
| #if SLI_SI91X_MCU_INTERFACE |
| // Required to invoke button press event during sleep as falling edge is not detected |
| void sl_si91x_invoke_btn_press_event(void) |
| { |
| // TODO: should be removed once we are getting the press interrupt for button 0 with sleep |
| if (!RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN) && !btn0_pressed) |
| { |
| sl_button_on_change(SL_BUTTON_BTN0_NUMBER, 1 /* Button Pressed */); |
| btn0_pressed = true; |
| } |
| if (RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN)) |
| { |
| btn0_pressed = false; |
| } |
| |
| #ifdef ENABLE_CHIP_SHELL |
| // Checking the UULP PIN 1 status to reinit the UART and not allow the device to go to sleep |
| if (RSI_NPSSGPIO_GetPin(RTE_UULP_GPIO_1_PIN)) |
| { |
| if (!ps_requirement_added) |
| { |
| sl_si91x_power_manager_add_ps_requirement(SL_SI91X_POWER_MANAGER_PS4); |
| ps_requirement_added = true; |
| } |
| } |
| else |
| { |
| if (ps_requirement_added) |
| { |
| sl_si91x_power_manager_remove_ps_requirement(SL_SI91X_POWER_MANAGER_PS4); |
| ps_requirement_added = false; |
| } |
| } |
| #endif // ENABLE_CHIP_SHELL |
| } |
| #endif // SLI_SI91X_MCU_INTERFACE |
| |
| /****************************************************************** |
| * @fn wfx_rsi_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) |
| * @brief |
| * Setting the RS911x in DTIM sleep based mode |
| * |
| * @param[in] sl_si91x_ble_state : State to set for the BLE |
| * @param[in] sl_si91x_wifi_state : State to set for the WiFi |
| * @return |
| * None |
| *********************************************************************/ |
| int32_t wfx_rsi_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) |
| { |
| int32_t status; |
| |
| status = rsi_bt_power_save_profile(sl_si91x_ble_state, 0); |
| if (status != RSI_SUCCESS) |
| { |
| ChipLogError(DeviceLayer, "rsi_bt_power_save_profile failed: 0x%lx", static_cast<uint32_t>(status)); |
| return status; |
| } |
| sl_wifi_performance_profile_t wifi_profile = { .profile = sl_si91x_wifi_state }; |
| status = sl_wifi_set_performance_profile(&wifi_profile); |
| if (status != RSI_SUCCESS) |
| { |
| ChipLogError(DeviceLayer, "sl_wifi_set_performance_profile failed: 0x%lx", static_cast<uint32_t>(status)); |
| return status; |
| } |
| |
| return status; |
| } |
| #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER */ |
| |
| sl_status_t show_scan_results(sl_wifi_scan_result_t * scan_result) |
| { |
| SL_WIFI_ARGS_CHECK_NULL_POINTER(scan_result); |
| VerifyOrReturnError(wfx_rsi.scan_cb != nullptr, SL_STATUS_INVALID_HANDLE); |
| |
| wfx_wifi_scan_result_t cur_scan_result; |
| for (int idx = 0; idx < (int) scan_result->scan_count; idx++) |
| { |
| memset(&cur_scan_result, 0, sizeof(cur_scan_result)); |
| |
| cur_scan_result.ssid_length = strnlen((char *) scan_result->scan_info[idx].ssid, |
| std::min<size_t>(sizeof(scan_result->scan_info[idx].ssid), WFX_MAX_SSID_LENGTH)); |
| chip::Platform::CopyString(cur_scan_result.ssid, cur_scan_result.ssid_length, (char *) scan_result->scan_info[idx].ssid); |
| |
| // if user has provided ssid, then check if the current scan result ssid matches the user provided ssid |
| if (wfx_rsi.scan_ssid != nullptr && |
| (strncmp(wfx_rsi.scan_ssid, cur_scan_result.ssid, std::min(strlen(wfx_rsi.scan_ssid), strlen(cur_scan_result.ssid))) == |
| CMP_SUCCESS)) |
| { |
| continue; |
| } |
| cur_scan_result.security = static_cast<wfx_sec_t>(scan_result->scan_info[idx].security_mode); |
| cur_scan_result.rssi = (-1) * scan_result->scan_info[idx].rssi_val; |
| memcpy(cur_scan_result.bssid, scan_result->scan_info[idx].bssid, BSSID_LEN); |
| wfx_rsi.scan_cb(&cur_scan_result); |
| |
| // if user has not provided the ssid, then call the callback for each scan result |
| if (wfx_rsi.scan_ssid == nullptr) |
| { |
| continue; |
| } |
| break; |
| } |
| |
| // cleanup and return |
| wfx_rsi.dev_state &= ~WFX_RSI_ST_SCANSTARTED; |
| wfx_rsi.scan_cb((wfx_wifi_scan_result_t *) 0); |
| wfx_rsi.scan_cb = nullptr; |
| if (wfx_rsi.scan_ssid) |
| { |
| chip::Platform::MemoryFree(wfx_rsi.scan_ssid); |
| wfx_rsi.scan_ssid = nullptr; |
| } |
| return SL_STATUS_OK; |
| } |
| |
| sl_status_t bg_scan_callback_handler(sl_wifi_event_t event, sl_wifi_scan_result_t * result, uint32_t result_length, void * arg) |
| { |
| show_scan_results(result); // To do Check error |
| osSemaphoreRelease(sScanCompleteSemaphore); |
| return SL_STATUS_OK; |
| } |
| |
| /// NotifyConnectivity |
| /// @brief Notify the application about the connectivity status if it has not been notified yet. |
| /// Helper function for HandleDHCPPolling. |
| void NotifyConnectivity(void) |
| { |
| VerifyOrReturn(!hasNotifiedWifiConnectivity); |
| wfx_connected_notify(CONNECTION_STATUS_SUCCESS, &wfx_rsi.ap_mac); |
| hasNotifiedWifiConnectivity = true; |
| } |
| |
| void HandleDHCPPolling(void) |
| { |
| WfxEvent_t event; |
| |
| // TODO: Notify the application that the interface is not set up or Chipdie here because we are in an unkonwn state |
| struct netif * sta_netif = &wifi_client_context.netif; |
| VerifyOrReturn(sta_netif != nullptr, ChipLogError(DeviceLayer, "HandleDHCPPolling: failed to get STA netif")); |
| |
| #if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) |
| uint8_t dhcp_state = dhcpclient_poll(sta_netif); |
| if (dhcp_state == DHCP_ADDRESS_ASSIGNED && !hasNotifiedIPV4) |
| { |
| wfx_dhcp_got_ipv4((uint32_t) sta_netif->ip_addr.u_addr.ip4.addr); |
| hasNotifiedIPV4 = true; |
| event.eventType = WFX_EVT_STA_DHCP_DONE; |
| sl_matter_wifi_post_event(&event); |
| NotifyConnectivity(); |
| } |
| else if (dhcp_state == DHCP_OFF) |
| { |
| wfx_ip_changed_notify(IP_STATUS_FAIL); |
| hasNotifiedIPV4 = false; |
| } |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ |
| /* Checks if the assigned IPv6 address is preferred by evaluating |
| * the first block of IPv6 address ( block 0) |
| */ |
| if ((ip6_addr_ispreferred(netif_ip6_addr_state(sta_netif, 0))) && !hasNotifiedIPV6) |
| { |
| char addrStr[chip::Inet::IPAddress::kMaxStringLength] = { 0 }; |
| VerifyOrReturn(ip6addr_ntoa_r(netif_ip6_addr(sta_netif, 0), addrStr, sizeof(addrStr)) != nullptr); |
| ChipLogProgress(DeviceLayer, "SLAAC OK: linklocal addr: %s", addrStr); |
| wfx_ipv6_notify(GET_IPV6_SUCCESS); |
| hasNotifiedIPV6 = true; |
| event.eventType = WFX_EVT_STA_DHCP_DONE; |
| sl_matter_wifi_post_event(&event); |
| NotifyConnectivity(); |
| } |
| } |
| |
| void sl_matter_wifi_post_event(WfxEvent_t * event) |
| { |
| if (osMessageQueuePut(sWifiEventQueue, event, 0, 0) != osOK) |
| { |
| ChipLogError(DeviceLayer, "sl_matter_wifi_post_event: failed to post event.") |
| // TODO: Handle error, requeue event depending on queue size or notify relevant task, Chipdie, etc. |
| } |
| } |
| |
| /// ResetDHCPNotificationFlags |
| /// @brief Reset the flags that are used to notify the application about DHCP connectivity |
| /// and emits a WFX_EVT_STA_DO_DHCP event to trigger DHCP polling checks. Helper function for ProcessEvent. |
| void ResetDHCPNotificationFlags(void) |
| { |
| WfxEvent_t outEvent; |
| |
| #if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) |
| hasNotifiedIPV4 = false; |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4 |
| hasNotifiedIPV6 = false; |
| hasNotifiedWifiConnectivity = false; |
| |
| outEvent.eventType = WFX_EVT_STA_DO_DHCP; |
| sl_matter_wifi_post_event(&outEvent); |
| } |
| |
| void ProcessEvent(WfxEvent_t inEvent) |
| { |
| // Process event |
| switch (inEvent.eventType) |
| { |
| case WFX_EVT_STA_CONN: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_STA_CONN"); |
| wfx_rsi.dev_state |= WFX_RSI_ST_STA_CONNECTED; |
| ResetDHCPNotificationFlags(); |
| |
| break; |
| |
| case WFX_EVT_STA_DISCONN: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_STA_DISCONN"); |
| // TODO: This event is not being posted anywhere, seems to be a dead code or we are missing something |
| wfx_rsi.dev_state &= |
| ~(WFX_RSI_ST_STA_READY | WFX_RSI_ST_STA_CONNECTING | WFX_RSI_ST_STA_CONNECTED | WFX_RSI_ST_STA_DHCP_DONE); |
| /* TODO: Implement disconnect notify */ |
| ResetDHCPNotificationFlags(); |
| #if (CHIP_DEVICE_CONFIG_ENABLE_IPV4) |
| wfx_ip_changed_notify(0); // for IPV4 |
| wfx_ip_changed_notify(IP_STATUS_FAIL); |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ |
| wfx_ipv6_notify(GET_IPV6_FAIL); |
| break; |
| |
| case WFX_EVT_AP_START: |
| // TODO: Currently unimplemented |
| break; |
| case WFX_EVT_AP_STOP: |
| // TODO: Currently unimplemented |
| break; |
| |
| case WFX_EVT_SCAN: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_SCAN"); |
| |
| #ifdef SL_WFX_CONFIG_SCAN |
| if (!(wfx_rsi.dev_state & WFX_RSI_ST_SCANSTARTED)) |
| { |
| ChipLogDetail(DeviceLayer, "WFX_EVT_SCAN"); |
| sl_wifi_scan_configuration_t wifi_scan_configuration; |
| memset(&wifi_scan_configuration, 0, sizeof(wifi_scan_configuration)); |
| |
| // TODO: Add scan logic |
| sl_wifi_advanced_scan_configuration_t advanced_scan_configuration = { 0 }; |
| int32_t status; |
| advanced_scan_configuration.active_channel_time = kAdvActiveScanDuration; |
| advanced_scan_configuration.passive_channel_time = kAdvPassiveScanDuration; |
| advanced_scan_configuration.trigger_level = kAdvScanThreshold; |
| advanced_scan_configuration.trigger_level_change = kAdvRssiToleranceThreshold; |
| advanced_scan_configuration.enable_multi_probe = kAdvMultiProbe; |
| status = sl_wifi_set_advanced_scan_configuration(&advanced_scan_configuration); |
| if (SL_STATUS_OK != status) |
| { |
| // TODO: Seems like Chipdie should be called here, the device should be initialized here |
| ChipLogError(DeviceLayer, "sl_wifi_set_advanced_scan_configuration failed: 0x%lx", static_cast<uint32_t>(status)); |
| return; |
| } |
| |
| if (wfx_rsi.dev_state & WFX_RSI_ST_STA_CONNECTED) |
| { |
| /* Terminate with end of scan which is no ap sent back */ |
| wifi_scan_configuration.type = SL_WIFI_SCAN_TYPE_ADV_SCAN; |
| wifi_scan_configuration.periodic_scan_interval = kAdvScanPeriodicity; |
| } |
| else |
| { |
| wifi_scan_configuration = default_wifi_scan_configuration; |
| } |
| sl_wifi_set_scan_callback(bg_scan_callback_handler, nullptr); |
| wfx_rsi.dev_state |= WFX_RSI_ST_SCANSTARTED; |
| |
| osSemaphoreAcquire(sScanInProgressSemaphore, osWaitForever); |
| status = sl_wifi_start_scan(SL_WIFI_CLIENT_2_4GHZ_INTERFACE, nullptr, &wifi_scan_configuration); |
| if (SL_STATUS_IN_PROGRESS == status) |
| { |
| osSemaphoreAcquire(sScanCompleteSemaphore, kWifiScanTimeoutTicks); |
| } |
| |
| osSemaphoreRelease(sScanInProgressSemaphore); |
| } |
| #endif /* SL_WFX_CONFIG_SCAN */ |
| break; |
| case WFX_EVT_STA_START_JOIN: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_STA_START_JOIN"); |
| |
| // Trigger Netwrok scan |
| InitiateScan(); |
| |
| // Joining to the network |
| JoinWifiNetwork(); |
| break; |
| |
| case WFX_EVT_STA_DO_DHCP: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_STA_DO_DHCP"); |
| StartDHCPTimer(WFX_RSI_DHCP_POLL_INTERVAL); |
| break; |
| case WFX_EVT_STA_DHCP_DONE: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_STA_DHCP_DONE"); |
| CancelDHCPTimer(); |
| break; |
| case WFX_EVT_DHCP_POLL: |
| ChipLogDetail(DeviceLayer, "WFX_EVT_DHCP_POLL"); |
| HandleDHCPPolling(); |
| default: |
| break; |
| } |
| } |
| |
| /** |
| * @brief Wifi initialization called from app main |
| * |
| * @return sl_status_t Returns underlying Wi-Fi initialization error |
| */ |
| sl_status_t sl_matter_wifi_platform_init(void) |
| { |
| sl_status_t status = SL_STATUS_OK; |
| |
| status = sl_net_init((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE, &config, &wifi_client_context, nullptr); |
| VerifyOrReturnError(status == SL_STATUS_OK, status, ChipLogError(DeviceLayer, "sl_net_init failed: %lx", status)); |
| |
| // Create Sempaphore for scan completion |
| sScanCompleteSemaphore = osSemaphoreNew(1, 0, nullptr); |
| VerifyOrReturnError(sScanCompleteSemaphore != nullptr, SL_STATUS_ALLOCATION_FAILED); |
| |
| // Create Semaphore for scan in-progress protection |
| sScanInProgressSemaphore = osSemaphoreNew(1, 1, nullptr); |
| VerifyOrReturnError(sScanCompleteSemaphore != nullptr, SL_STATUS_ALLOCATION_FAILED); |
| |
| // Create the message queue |
| sWifiEventQueue = osMessageQueueNew(kWfxQueueSize, sizeof(WfxEvent_t), nullptr); |
| VerifyOrReturnError(sWifiEventQueue != nullptr, SL_STATUS_ALLOCATION_FAILED); |
| |
| // Create timer for DHCP polling |
| // TODO: Use LWIP timer instead of creating a new one here |
| sDHCPTimer = osTimerNew(DHCPTimerEventHandler, osTimerPeriodic, nullptr, nullptr); |
| VerifyOrReturnError(sDHCPTimer != nullptr, SL_STATUS_ALLOCATION_FAILED); |
| |
| return status; |
| } |
| |
| /********************************************************************************* |
| * @fn void sl_matter_wifi_task(void *arg) |
| * @brief |
| * The main WLAN task - started by wfx_wifi_start() that interfaces with RSI. |
| * The rest of RSI stuff come in call-backs. |
| * The initialization has been already done. |
| * @param[in] arg: |
| * @return |
| * None |
| **********************************************************************************/ |
| /* ARGSUSED */ |
| void sl_matter_wifi_task(void * arg) |
| { |
| (void) arg; |
| WfxEvent_t wfxEvent; |
| sl_status_t status = SL_STATUS_OK; |
| |
| status = sl_wifi_siwx917_init(); |
| VerifyOrReturn( |
| status == SL_STATUS_OK, |
| ChipLogError(DeviceLayer, "sl_matter_wifi_task: sl_wifi_siwx917_init failed: 0x%lx", static_cast<uint32_t>(status))); |
| |
| sl_matter_wifi_task_started(); |
| |
| ChipLogDetail(DeviceLayer, "sl_matter_wifi_task: starting event loop"); |
| for (;;) |
| { |
| if (osMessageQueueGet(sWifiEventQueue, &wfxEvent, nullptr, osWaitForever) == osOK) |
| { |
| ProcessEvent(wfxEvent); |
| } |
| else |
| { |
| ChipLogError(DeviceLayer, "sl_matter_wifi_task: get event failed: 0x%lx", static_cast<uint32_t>(status)); |
| } |
| } |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_IPV4 |
| /******************************************************************************************** |
| * @fn void wfx_dhcp_got_ipv4(uint32_t ip) |
| * @brief |
| * Acquire the new ip address |
| * @param[in] ip: internet protocol |
| * @return |
| * None |
| **********************************************************************************************/ |
| void wfx_dhcp_got_ipv4(uint32_t ip) |
| { |
| /* |
| * Acquire the new IP address |
| */ |
| wfx_rsi.ip4_addr[0] = (ip) &HEX_VALUE_FF; |
| wfx_rsi.ip4_addr[1] = (ip >> 8) & HEX_VALUE_FF; |
| wfx_rsi.ip4_addr[2] = (ip >> 16) & HEX_VALUE_FF; |
| wfx_rsi.ip4_addr[3] = (ip >> 24) & HEX_VALUE_FF; |
| ChipLogDetail(DeviceLayer, "DHCP OK: IP=%d.%d.%d.%d", wfx_rsi.ip4_addr[0], wfx_rsi.ip4_addr[1], wfx_rsi.ip4_addr[2], |
| wfx_rsi.ip4_addr[3]); |
| /* Notify the Connectivity Manager - via the app */ |
| wfx_rsi.dev_state |= WFX_RSI_ST_STA_DHCP_DONE; |
| wfx_ip_changed_notify(IP_STATUS_SUCCESS); |
| wfx_rsi.dev_state |= WFX_RSI_ST_STA_READY; |
| } |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ |