/***************************************************************************/ /**
* @file
* @brief
*******************************************************************************
* # License
* Copyright 2024 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_wifi.h"
#include "sl_si91x_host_interface.h"
#include "sl_wifi_types.h"
#include "sl_si91x_status.h"
#include "sl_si91x_types.h"
#include "sl_si91x_protocol_types.h"
#include "sl_wifi_device.h"
#include "sl_rsi_utility.h"
#include "sl_si91x_driver.h"
#include "cmsis_os2.h"
#include
#include
#include
#include "sl_si91x_core_utilities.h"
#include "em_core.h"
#ifdef SLI_SI91X_MCU_INTERFACE
#include "sli_siwx917_soc.h"
#include "rsi_rom_clks.h"
#include "rsi_m4.h"
#include "rsi_wisemcu_hardware_setup.h"
#endif
#ifdef SLI_SI91X_ENABLE_BLE
#include "rsi_common_apis.h"
#endif
#include "sl_wifi_region_db_config.h"
#ifdef SLI_SI91X_SOCKETS
#include "sl_si91x_socket_utility.h"
#include "sl_si91x_socket_callback_framework.h"
#endif
#ifdef SL_SI91X_SIDE_BAND_CRYPTO
#include "rsi_m4.h"
#define SIDE_BAND_DONE (1 << 2) //! had to be redefined as this macro is not in .h
rsi_m4ta_desc_t crypto_desc[2];
extern osEventFlagsId_t ta_events;
extern osMutexId_t side_band_crypto_mutex;
#endif
#ifndef NULL
#define NULL (void *)0
#endif
#define htole16(x) (x)
#define htole32(x) (x)
#ifndef SL_WIFI_SET_MAC_COMMAND_TIME_OUT
#define SL_WIFI_SET_MAC_COMMAND_TIME_OUT 30100 // Retrieved from SAPI 1.0
#endif
#define SLI_SI91X_GET_TCP_IP_TOTAL_SELECTS_BITS(x) ((x & 0x0000F000) >> 12)
#define SL_SI91X_INVALID_MODE 0xFFFF
#ifdef SL_SI91X_SIDE_BAND_CRYPTO
#define SL_HOST_DESC_LEN 16
#define SL_CRYPTO_PKT_LEN 128
#endif
// Enterprise configuration command parameters
/*=======================================================================*/
// Enterprise method ,should be one of among TLS, TTLS, FAST or PEAP
#define SL_EAP_TLS_METHOD "TLS"
#define SL_EAP_TTLS_METHOD "TTLS"
// This parameter is used to configure the module in Enterprise security mode
#define SL_EAP_INNER_METHOD "\"auth=MSCHAPV2\""
// Private Key Password is required for encrypted private key, format is like "\"12345678\""
#define SL_DEFAULT_PRIVATE_KEY_PASSWORD ""
/*========================================================================*/
// 11ax params
/*========================================================================*/
#define GUARD_INTERVAL 3
#ifdef SLI_SI91X_MCU_INTERFACE
#define TX_PKT_TRANSFER_DONE_INTERRUPT BIT(2)
#define RX_PKT_TRANSFER_DONE_INTERRUPT BIT(1)
// Function declarations related to M4 interface
sl_status_t sli_si91x_submit_rx_pkt(void);
static sl_status_t sl_si91x_soft_reset(void);
void sli_siwx917_update_system_core_clock(void);
void sli_m4_ta_interrupt_init(void);
#endif
// Structure to hold packet information and payload
typedef struct {
uint16_t packet_id;
sli_si91x_queue_packet_t *packet;
void *payload;
} sl_si91x_driver_context_t;
static sl_si91x_timeout_t timeout_glbl = { .auth_assoc_timeout_value = SL_WIFI_DEFAULT_AUTH_ASSOCIATION_TIMEOUT,
.active_chan_scan_timeout_value = SL_WIFI_DEFAULT_ACTIVE_CHANNEL_SCAN_TIME,
.keep_alive_timeout_value = SL_WIFI_DEFAULT_KEEP_ALIVE_TIMEOUT,
.passive_scan_timeout_value = SL_WIFI_DEFAULT_PASSIVE_CHANNEL_SCAN_TIME };
sl_status_t sl_si91x_driver_send_command_packet(uint32_t command,
sl_si91x_command_type_t command_type,
sl_wifi_buffer_t *buffer,
sl_si91x_wait_period_t wait_period,
void *sdk_context,
sl_wifi_buffer_t **data_buffer);
static sl_status_t sl_si91x_driver_send_data_packet(sl_wifi_buffer_t *buffer, uint32_t wait_time);
sl_status_t sl_si91x_driver_raw_send_command(uint8_t command,
const void *data,
uint32_t data_length,
uint32_t wait_time);
sl_status_t sl_si91x_allocate_data_buffer(sl_wifi_buffer_t **host_buffer,
void **buffer,
uint32_t data_size,
uint32_t wait_duration_ms);
sl_status_t sl_si91x_driver_init_wifi_radio(const sl_wifi_device_configuration_t *config);
sl_status_t sli_verify_device_boot(uint32_t *rom_version);
sl_status_t sl_si91x_enable_radio(void);
sl_status_t sli_wifi_select_option(const uint8_t configuration);
sl_status_t si91x_bootup_firmware(const uint8_t select_option);
sl_status_t sl_si91x_host_power_cycle(void);
// This variable stores the frame status of response packet in case of API executed being failed.
// Note: This will not store the error values of asynchronous events.
sl_wifi_event_handler_t si91x_event_handler = NULL;
// Global variables for device and driver management
sl_wifi_interface_t default_interface;
bool device_initialized = false;
bool interface_is_up[SL_WIFI_MAX_INTERFACE_INDEX] = { false, false, false, false, false };
bool bg_enabled = false;
uint32_t frontend_switch_control = 0;
static uint32_t feature_bit_map = 0;
//static uint16_t queue_packet_id[SI91X_CMD_MAX] = { 0 };
static uint8_t ap_join_feature_bitmap = SL_SI91X_JOIN_FEAT_LISTEN_INTERVAL_VALID;
static uint8_t client_join_feature_bitmap = SL_SI91X_JOIN_FEAT_LISTEN_INTERVAL_VALID;
static uint32_t client_listen_interval = 1000;
static sl_si91x_efuse_data_t si91x_efuse_data = { 0 };
//! Currently, initialized_opermode is used only to handle concurrent mode using sl_net_init()
static uint16_t initialized_opermode = SL_SI91X_INVALID_MODE;
extern sli_si91x_command_queue_t cmd_queues[SI91X_CMD_MAX];
extern sl_si91x_buffer_queue_t sli_tx_data_queue;
sli_si91x_performance_profile_t performance_profile;
extern osEventFlagsId_t si91x_events;
extern volatile uint32_t tx_command_queues_status;
extern volatile uint32_t tx_generic_socket_data_queues_status;
#ifdef SLI_SI91X_ENABLE_BLE
//! Memory length for driver
#define GLOBAL_BUFF_LEN 1500
//! Memory to initialize driver
uint8_t global_buf[GLOBAL_BUFF_LEN] = { 0 };
#endif
// clang-format off
const sl_wifi_scan_configuration_t default_wifi_scan_configuration = { .type = SL_WIFI_SCAN_TYPE_ACTIVE,
.flags = 0,
.periodic_scan_interval = 0,
.channel_bitmap_2g4 = 0xFFFF,
.channel_bitmap_5g = { 0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF },
.lp_mode = 0};
// clang-format on
const sl_wifi_buffer_configuration_t default_buffer_configuration = {
.control_buffer_quota = 10,
.tx_buffer_quota = 10,
.rx_buffer_quota = 10,
#ifdef SPI_EXTENDED_TX_LEN_2K
.block_size = 2300,
#else
.block_size = 1616,
#endif
.buffer_memory = NULL,
};
const sl_wifi_ap_configuration_t default_wifi_ap_configuration = {
.ssid = { .value = "SILICON_LABS_AP", .length = sizeof("SILICON_LABS_AP") - 1 },
.security = SL_WIFI_WPA2,
.encryption = SL_WIFI_CCMP_ENCRYPTION,
.channel = { .channel = 11 },
.rate_protocol = SL_WIFI_RATE_PROTOCOL_AUTO,
.options = 0,
.credential_id = 2, //SL_NET_DEFAULT_WIFI_AP_CREDENTIAL_ID,
.keepalive_type = SL_SI91X_AP_NULL_BASED_KEEP_ALIVE,
.beacon_interval = 100,
.client_idle_timeout = 120000,
.dtim_beacon_count = 4,
.maximum_clients = 4
};
// clang-format off
static uint8_t firmware_queue_id[SI91X_CMD_MAX] = { [SI91X_COMMON_CMD] = RSI_WLAN_MGMT_Q,
[SI91X_WLAN_CMD] = RSI_WLAN_MGMT_Q,
[SI91X_NETWORK_CMD] = RSI_WLAN_MGMT_Q,
[SI91X_SOCKET_CMD] = RSI_WLAN_MGMT_Q,
[SI91X_BT_CMD] = RSI_BT_Q };
//static uint32_t response_event_map[SI91X_CMD_MAX] = { [SI91X_COMMON_CMD] = NCP_HOST_COMMON_RESPONSE_EVENT,
// [SI91X_WLAN_CMD] = NCP_HOST_WLAN_RESPONSE_EVENT,
// [SI91X_NETWORK_CMD] = NCP_HOST_NETWORK_RESPONSE_EVENT,
// [SI91X_SOCKET_CMD] = NCP_HOST_SOCKET_RESPONSE_EVENT,
// [SI91X_BT_CMD] = NCP_HOST_BT_RESPONSE_EVENT };
// clang-format on
#ifdef SLI_SI91X_MCU_INTERFACE
extern sl_wifi_buffer_t *rx_pkt_buffer;
#endif
static bool si91x_packet_identification_function(const sl_wifi_buffer_t *buffer, const void *user_data)
{
const uint8_t *packet_id = (const uint8_t *)user_data;
// Check if the packet's packet ID matches the expected one
return (*packet_id == buffer->id);
}
void sl_si91x_get_efuse_data(sl_si91x_efuse_data_t *efuse_data)
{
memcpy(efuse_data, &si91x_efuse_data, sizeof(sl_si91x_efuse_data_t));
}
void sl_si91x_set_efuse_data(const sl_si91x_efuse_data_t *efuse_data)
{
memcpy(&si91x_efuse_data, efuse_data, sizeof(sl_si91x_efuse_data_t));
}
sl_status_t sl_si91x_driver_init_wifi_radio(const sl_wifi_device_configuration_t *config)
{
sl_status_t status;
// Set 11ax configuration with guard interval if SLI_SI91X_CONFIG_WIFI6_PARAMS is supported
#ifdef SLI_SI91X_CONFIG_WIFI6_PARAMS
status = sl_wifi_set_11ax_config(GUARD_INTERVAL);
VERIFY_STATUS_AND_RETURN(status);
#endif
// Send WLAN request to set the operating band (2.4GHz or 5GHz)
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_BAND,
SI91X_WLAN_CMD,
&config->band,
1,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
if (config->boot_config.oper_mode != SL_SI91X_ACCESS_POINT_MODE) {
if (timeout_glbl.active_chan_scan_timeout_value != SL_WIFI_DEFAULT_ACTIVE_CHANNEL_SCAN_TIME) {
status =
sl_si91x_configure_timeout(SL_SI91X_CHANNEL_ACTIVE_SCAN_TIMEOUT, timeout_glbl.active_chan_scan_timeout_value);
VERIFY_STATUS_AND_RETURN(status);
}
if (timeout_glbl.auth_assoc_timeout_value != SL_WIFI_DEFAULT_AUTH_ASSOCIATION_TIMEOUT) {
status =
sl_si91x_configure_timeout(SL_SI91X_AUTHENTICATION_ASSOCIATION_TIMEOUT, timeout_glbl.auth_assoc_timeout_value);
VERIFY_STATUS_AND_RETURN(status);
}
if (timeout_glbl.keep_alive_timeout_value != SL_WIFI_DEFAULT_KEEP_ALIVE_TIMEOUT) {
status = sl_si91x_configure_timeout(SL_SI91X_KEEP_ALIVE_TIMEOUT, timeout_glbl.keep_alive_timeout_value);
VERIFY_STATUS_AND_RETURN(status);
}
if (timeout_glbl.passive_scan_timeout_value != SL_WIFI_DEFAULT_PASSIVE_CHANNEL_SCAN_TIME) {
status =
sl_si91x_configure_timeout(SL_SI91X_CHANNEL_PASSIVE_SCAN_TIMEOUT, timeout_glbl.passive_scan_timeout_value);
VERIFY_STATUS_AND_RETURN(status);
}
}
// Initialize the WLAN subsystem
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_INIT,
SI91X_WLAN_CMD,
NULL,
0,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
#ifndef SL_SI91X_ACX_MODULE
if (IGNORE_REGION != config->region_code) {
// Set the device's region based on configuration
status = sl_si91x_set_device_region(config->boot_config.oper_mode, config->band, config->region_code);
VERIFY_STATUS_AND_RETURN(status);
}
#endif
// Configure the RTS threshold for WLAN
sl_si91x_config_request_t config_request = { .config_type = CONFIG_RTSTHRESHOLD, .value = RSI_RTS_THRESHOLD };
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_CONFIG,
SI91X_WLAN_CMD,
&config_request,
sizeof(config_request),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_driver_init(const sl_wifi_device_configuration_t *config, sl_wifi_event_handler_t event_handler)
{
sl_status_t status;
sl_si91x_host_init_configuration init_config = { 0 };
const uint8_t select_option = config->boot_option;
if (config->boot_config.coex_mode == SL_SI91X_WLAN_MODE) { // Check for not support mode
return SL_STATUS_NOT_SUPPORTED;
}
// Determine the default interface based on operating mode (AP or Client)
if (config->boot_config.oper_mode == SL_SI91X_ACCESS_POINT_MODE) {
default_interface = SL_WIFI_AP_INTERFACE;
} else {
default_interface = SL_WIFI_CLIENT_INTERFACE;
}
// Configure the interface for 5GHz band if selected (currently not supported for Si91x)
if (config->band == SL_SI91X_WIFI_BAND_5GHZ) {
default_interface |= SL_WIFI_5GHZ_INTERFACE;
} else {
default_interface |= SL_WIFI_2_4GHZ_INTERFACE;
}
// Set the event handler for the SI91x wireless driver
si91x_event_handler = event_handler;
// Check if the device is already initialized
if (device_initialized) {
// If it's already initialized, ensure the requested operating mode is compatible
if (initialized_opermode == SL_SI91X_CONCURRENT_MODE) {
return (initialized_opermode == config->boot_config.oper_mode) ? SL_STATUS_OK : SL_STATUS_WIFI_INVALID_OPERMODE;
}
return SL_STATUS_ALREADY_INITIALIZED;
}
// Initialize BLE if BLE is enabled
#ifdef SLI_SI91X_ENABLE_BLE
int32_t rsi_status = 0;
rsi_status = rsi_ble_driver_init(global_buf, GLOBAL_BUFF_LEN);
if ((rsi_status < 0) || (rsi_status > GLOBAL_BUFF_LEN)) {
return SL_STATUS_FAIL;
}
#endif
#ifndef SLI_SI91X_ENABLE_IPV6
uint32_t *tcp_ip_feature_bit_map = (uint32_t *)&(config->boot_config.tcp_ip_feature_bit_map);
// check if the module network stack is in IPV6 mode.
if (*tcp_ip_feature_bit_map & (SI91X_IPV6_MODE)) {
return SL_STATUS_NOT_AVAILABLE;
}
#endif
// Initialize the buffer manager
status = sl_si91x_host_init_buffer_manager(&default_buffer_configuration);
if (status != SL_STATUS_OK) {
return status;
}
init_config.rx_irq = sl_si91x_bus_rx_irq_handler;
init_config.rx_done = sl_si91x_bus_rx_done_handler;
init_config.boot_option = config->boot_option;
// Initialize the SI91x host
status = sl_si91x_host_init(&init_config);
VERIFY_STATUS_AND_RETURN(status);
// Initialize the SI91x platform
status = sl_si91x_platform_init();
VERIFY_STATUS_AND_RETURN(status);
// Power cycle the SI91x device
status = sl_si91x_host_power_cycle();
VERIFY_STATUS_AND_RETURN(status);
// sl_si91x_bus_init() will be implemented for all available buses
status = sl_si91x_bus_init();
VERIFY_STATUS_AND_RETURN(status);
#ifdef SLI_SI91X_MCU_INTERFACE
// firmware bootup is require only for the first time, no need to do it again if we call init after deinit
static bool is_bootup_firmware_required = true;
if (is_bootup_firmware_required) {
status = si91x_bootup_firmware(select_option);
VERIFY_STATUS_AND_RETURN(status);
is_bootup_firmware_required = false;
} else {
// Initialize NWP interrupt and submit RX packets
sli_m4_ta_interrupt_init();
sli_si91x_submit_rx_pkt();
}
#else
status = si91x_bootup_firmware(select_option);
VERIFY_STATUS_AND_RETURN(status);
#endif
// Initialize task register index to save firmware status
status = sli_fw_status_storage_index_init();
VERIFY_STATUS_AND_RETURN(status);
#ifdef SL_SI91X_SPI_HIGH_SPEED_ENABLE
// Enable high speed bus on the device and the host
status = sl_si91x_bus_enable_high_speed();
VERIFY_STATUS_AND_RETURN(status);
sl_si91x_host_enable_high_speed_bus();
#endif
sl_si91x_host_enable_bus_interrupt();
// Wait for card ready command response
#ifdef SLI_SI91X_MCU_INTERFACE
// NWP would not send card ready command response, if we call init after deinit
if (get_card_ready_required()) {
uint32_t events = sli_si91x_wait_for_event(NCP_HOST_COMMON_RESPONSE_EVENT, 5000);
if (!(events & NCP_HOST_COMMON_RESPONSE_EVENT)) {
return SL_STATUS_CARD_READY_TIMEOUT;
}
set_card_ready_required(false);
}
#else
uint32_t events = sli_si91x_wait_for_event(NCP_HOST_COMMON_RESPONSE_EVENT, 3000);
if (!(events & NCP_HOST_COMMON_RESPONSE_EVENT)) {
return SL_STATUS_CARD_READY_TIMEOUT;
}
#endif
// Send WLAN request to set the operating mode and configuration
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_OPERMODE,
SI91X_COMMON_CMD,
&config->boot_config,
sizeof(sl_si91x_boot_configuration_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
#ifdef SL_WDT_MANAGER_PRESENT
sl_si91x_nwp_configuration_t nwp_config;
// NWP WDT configuration
memset(&nwp_config, 0, sizeof(sl_si91x_nwp_configuration_t));
nwp_config.code = SL_SI91X_ENABLE_NWP_WDT_FROM_HOST;
nwp_config.values.wdt_timer_val = 0x20;
nwp_config.values.wdt_enable_in_ps = 0;
status = sl_si91x_set_nwp_config_request(nwp_config);
VERIFY_STATUS_AND_RETURN(status);
#endif
feature_bit_map = config->boot_config.feature_bit_map;
#ifdef SLI_SI91X_ENABLE_BLE
if (config->boot_config.coex_mode == SL_SI91X_BLE_MODE || config->boot_config.coex_mode == SL_SI91X_WLAN_BLE_MODE) {
// Wait for BT card ready
rsi_bt_common_init();
}
#endif
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_DYNAMIC_POOL,
SI91X_WLAN_CMD,
&config->ta_pool,
sizeof(sl_si91x_dynamic_pool),
SL_SI91X_WAIT_FOR(30100),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
// Configure various wireless features
sl_si91x_feature_frame_request feature_frame_request = { .pll_mode = PLL_MODE,
.rf_type = RF_TYPE,
.wireless_mode = WIRELESS_MODE,
.enable_ppp = ENABLE_PPP,
.afe_type = AFE_TYPE,
.feature_enables = FEATURE_ENABLES };
// Setting PLL mode to 1 in case of high clock frequency
//pll_mode 1 is not supported in coex mode
if ((!config->boot_config.coex_mode)
&& (config->boot_config.custom_feature_bit_map
& (SL_SI91X_CUSTOM_FEAT_SOC_CLK_CONFIG_160MHZ | SL_SI91X_CUSTOM_FEAT_SOC_CLK_CONFIG_120MHZ))) {
feature_frame_request.pll_mode = 1;
} else {
feature_frame_request.pll_mode = 0;
}
// For the transmit test mode we need to disable BIT 0, 4, 5. These bitmaps are only required in powersave.
// To receive broadcast data packets in transceiver opermode, we need to enable BIT 1.
if (config->boot_config.oper_mode == SL_SI91X_TRANSMIT_TEST_MODE) {
feature_frame_request.feature_enables &= ~(FEATURE_ENABLES);
} else if (config->boot_config.oper_mode == SL_SI91X_TRANSCEIVER_MODE) {
feature_frame_request.feature_enables |= SI91X_FEAT_FRAME_PERMIT_UNDESTINED_PACKETS;
} else {
feature_frame_request.feature_enables = feature_frame_request.feature_enables;
}
// Dispatch a feature request frame to the SI91x driver
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_FEATURE_FRAME,
SI91X_COMMON_CMD,
&feature_frame_request,
sizeof(feature_frame_request),
SL_SI91X_WAIT_FOR(10000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
// if 16th bit of ext_tcp_ip_feature_bit_map is not set, then firmware auto closes the TCP socket on remote termination.
save_tcp_auto_close_choice(
(config->boot_config.ext_tcp_ip_feature_bit_map & SL_SI91X_EXT_TCP_IP_WAIT_FOR_SOCKET_CLOSE) == 0);
#ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
sli_si91x_socket_init(SLI_SI91X_GET_TCP_IP_TOTAL_SELECTS_BITS(config->boot_config.ext_tcp_ip_feature_bit_map));
VERIFY_STATUS_AND_RETURN(status);
#endif
// Set the MAC address if provided in the configuration
if (config->mac_address != NULL) {
status = sl_wifi_set_mac_address(default_interface, config->mac_address);
VERIFY_STATUS_AND_RETURN(status);
}
// Initialize the WiFi radio if the coexistence mode is not BLE
if (config->boot_config.coex_mode != SL_SI91X_BLE_MODE) {
status = sl_si91x_driver_init_wifi_radio(config);
VERIFY_STATUS_AND_RETURN(status);
}
// Check and update the frontend switch control based on custom feature bit map
if (config->boot_config.custom_feature_bit_map & SL_SI91X_CUSTOM_FEAT_EXTENSION_VALID) {
frontend_switch_control = (config->boot_config.ext_custom_feature_bit_map & (BIT(29) | (BIT(30))));
}
#ifdef SLI_SI91X_MCU_INTERFACE
// Program wireless GPIO front-end switch controls
if (frontend_switch_control != 0) {
sli_si91x_configure_wireless_frontend_controls(frontend_switch_control);
}
#endif
// Mark the device as initialized
device_initialized = true;
initialized_opermode = config->boot_config.oper_mode;
// Set interface status flags based on operating mode and band
if ((config->boot_config.oper_mode == SL_SI91X_CLIENT_MODE)
|| (config->boot_config.oper_mode == SL_SI91X_ENTERPRISE_CLIENT_MODE)
|| (config->boot_config.oper_mode == SL_SI91X_CONCURRENT_MODE)
|| (config->boot_config.oper_mode == SL_SI91X_TRANSMIT_TEST_MODE)) {
if (config->band == SL_SI91X_WIFI_BAND_2_4GHZ) {
interface_is_up[SL_WIFI_CLIENT_2_4GHZ_INTERFACE_INDEX] = true;
} else if (config->band == SL_SI91X_WIFI_BAND_5GHZ) {
interface_is_up[SL_WIFI_CLIENT_5GHZ_INTERFACE_INDEX] = true;
}
}
// Save the coexistence mode in the driver
save_coex_mode(config->boot_config.coex_mode);
#ifdef SL_SI91X_GET_EFUSE_DATA
status = sl_si91x_get_flash_efuse_data(&si91x_efuse_data, config->efuse_data_type);
#endif
#ifdef SLI_SI91X_MCU_INTERFACE
if (status == SL_STATUS_OK) {
/* send a notification to the NWP indicating whether the M4 core is currently utilizing the XTAL as its clock source*/
sli_si91x_send_m4_xtal_usage_notification_to_ta();
}
#endif
return status;
}
sl_status_t sl_si91x_driver_deinit(void)
{
sl_status_t status = SL_STATUS_OK;
// Check if the device has been initialized if not, return an error
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
#ifdef SLI_SI91X_MCU_INTERFACE
// If the SLI_SI91X_MCU_INTERFACE is defined, perform a soft reset
status = sl_si91x_soft_reset();
VERIFY_STATUS_AND_RETURN(status);
// Mask specific interrupts related to packet transfer
mask_ta_interrupt(TX_PKT_TRANSFER_DONE_INTERRUPT | RX_PKT_TRANSFER_DONE_INTERRUPT);
#endif
#ifdef SLI_SI91X_ENABLE_BLE
int32_t rsi_status = 0;
// If SLI_SI91X_ENABLE_BLE is defined, deinitialize the BLE driver and check for errors
rsi_status = rsi_ble_driver_deinit();
if (rsi_status != RSI_SUCCESS) {
return SL_STATUS_FAIL;
}
#endif
// Flush all TX Wi-Fi queues with the status indicating Wi-Fi connection is lost
sli_si91x_flush_all_tx_wifi_queues(SL_STATUS_WIFI_CONNECTION_LOST);
// Flush the generic TX data queue
sli_si91x_flush_generic_data_queues(&sli_tx_data_queue);
#if defined(SLI_SI91X_OFFLOAD_NETWORK_STACK) && defined(SLI_SI91X_SOCKETS)
// Flush all pending socket commands in the client VAP queue due to Wi-Fi connection loss
sli_si91x_flush_all_socket_command_queues(SL_STATUS_WIFI_CONNECTION_LOST, SL_SI91X_WIFI_CLIENT_VAP_ID);
// Flush all pending socket data in the client VAP queue due to Wi-Fi connection loss
sli_si91x_flush_all_socket_data_queues(SL_SI91X_WIFI_CLIENT_VAP_ID);
// Flush all pending socket commands in the AP VAP queue due to Wi-Fi connection loss
sli_si91x_flush_all_socket_command_queues(SL_STATUS_WIFI_CONNECTION_LOST, SL_SI91X_WIFI_AP_VAP_ID);
// Flush all pending socket data in the AP VAP queue due to Wi-Fi connection loss
sli_si91x_flush_all_socket_data_queues(SL_SI91X_WIFI_AP_VAP_ID);
// Shutdown and change the state of the client VAP sockets
status = sli_si91x_vap_shutdown(SL_SI91X_WIFI_CLIENT_VAP_ID);
VERIFY_STATUS_AND_RETURN(status);
// Shutdown and change the state of the AP VAP sockets
status = sli_si91x_vap_shutdown(SL_SI91X_WIFI_AP_VAP_ID);
VERIFY_STATUS_AND_RETURN(status);
// Deinitialize and free all socket-related resources
status = sli_si91x_socket_deinit();
VERIFY_STATUS_AND_RETURN(status);
#endif // End of check for offloaded network stack and sockets
// Deinitialize the SI91x platform
status = sl_si91x_platform_deinit();
VERIFY_STATUS_AND_RETURN(status);
// Deinitialize the SI91x host
status = sl_si91x_host_deinit();
VERIFY_STATUS_AND_RETURN(status);
#ifdef SLI_SI91X_MCU_INTERFACE
// Check the RX buffer valid bit is set or not.
if (M4SS_P2P_INTR_SET_REG & RX_BUFFER_VALID) {
// Clear the RX buffer valid bit.
M4SS_P2P_INTR_CLR_REG = (RX_BUFFER_VALID);
// Clear the RX buffer.
sl_si91x_host_free_buffer(rx_pkt_buffer);
}
#endif
// Deinitialize the buffer manager
status = sl_si91x_host_deinit_buffer_manager();
VERIFY_STATUS_AND_RETURN(status);
sl_si91x_host_disable_bus_interrupt();
status = sl_si91x_host_power_cycle();
VERIFY_STATUS_AND_RETURN(status);
// Clear the event handler and reset initialization status
si91x_event_handler = NULL;
device_initialized = false;
initialized_opermode = SL_SI91X_INVALID_MODE;
// Reset all the interfaces
memset(interface_is_up, 0, sizeof(interface_is_up));
return status;
}
sl_status_t sl_si91x_get_flash_efuse_data(sl_si91x_efuse_data_t *efuse_data, uint8_t efuse_data_type)
{
sl_status_t status;
sl_wifi_buffer_t *buffer = NULL;
SL_WIFI_ARGS_CHECK_NULL_POINTER(efuse_data);
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_GET_EFUSE_DATA,
SI91X_COMMON_CMD,
&efuse_data_type,
sizeof(efuse_data_type),
SL_SI91X_WAIT_FOR_RESPONSE(15000),
NULL,
&buffer);
if ((status != SL_STATUS_OK) && (buffer != NULL)) {
sl_si91x_host_free_buffer(buffer);
}
VERIFY_STATUS_AND_RETURN(status);
const sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
if (packet->length > 0) {
switch (efuse_data_type) {
case SL_SI91X_EFUSE_MFG_SW_VERSION:
memcpy(&efuse_data->mfg_sw_version, packet->data, packet->length);
break;
case SL_SI91X_EFUSE_PTE_CRC:
memcpy(&efuse_data->pte_crc, packet->data, packet->length);
break;
default:
break;
}
}
sl_si91x_host_free_buffer(buffer);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_driver_raw_send_command(uint8_t command,
const void *data,
uint32_t data_length,
uint32_t wait_time)
{
UNUSED_PARAMETER(wait_time);
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
sl_status_t status = SL_STATUS_OK;
// Allocate a data buffer with space for the data and metadata
status = sl_si91x_allocate_data_buffer(&buffer,
(void **)&packet,
sizeof(sl_si91x_packet_t) + data_length,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
// If the packet is not allocated successfully, return an allocation failed error
if (packet == NULL) {
return SL_STATUS_ALLOCATION_FAILED;
}
// Clear the packet descriptor and copy the command data if available
memset(packet->desc, 0, sizeof(packet->desc));
if (data != NULL) {
memcpy(packet->data, data, data_length);
}
packet->length = data_length & 0xFFF;
packet->command = command;
// Adding the packet to the queue with atomic action
return sl_si91x_driver_send_data_packet(buffer, wait_time);
}
sl_status_t sl_si91x_driver_send_socket_data(const sli_si91x_socket_send_request_t *request,
const void *data,
uint32_t wait_time)
{
UNUSED_PARAMETER(wait_time);
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
sli_si91x_socket_send_request_t *send;
sl_status_t status = SL_STATUS_OK;
uint16_t header_length = (request->data_offset - sizeof(sli_si91x_socket_send_request_t));
uint32_t data_length = request->length;
if (data == NULL) {
return SL_STATUS_NULL_POINTER;
}
// Allocate a buffer for the socket data with appropriate size
status = sl_si91x_host_allocate_buffer(
&buffer,
SL_WIFI_TX_FRAME_BUFFER,
sizeof(sl_si91x_packet_t) + sizeof(sli_si91x_socket_send_request_t) + header_length + data_length,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
// If the packet is not allocated successfully, return an allocation failed error
if (packet == NULL) {
return SL_STATUS_WIFI_BUFFER_ALLOC_FAIL;
}
memset(packet->desc, 0, sizeof(packet->desc));
send = (sli_si91x_socket_send_request_t *)packet->data;
memcpy(send, request, sizeof(sli_si91x_socket_send_request_t));
memcpy((send->send_buffer + header_length), data, data_length);
// Fill frame type
packet->length = (sizeof(sli_si91x_socket_send_request_t) + header_length + data_length) & 0xFFF;
return sl_si91x_driver_send_data_packet(buffer, wait_time);
}
sl_status_t sl_si91x_custom_driver_send_command(uint32_t command,
sl_si91x_command_type_t command_type,
const void *data,
uint32_t data_length,
sl_si91x_wait_period_t wait_period,
void *sdk_context,
sl_wifi_buffer_t **data_buffer,
uint8_t custom_host_desc)
{
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
sl_status_t status;
// Check if the queue type is within valid range
if (command_type >= SI91X_CMD_MAX) {
return SL_STATUS_INVALID_INDEX;
}
// Allocate a buffer for the command with appropriate size
status = sli_si91x_allocate_command_buffer(&buffer,
(void **)&packet,
sizeof(sl_si91x_packet_t) + data_length,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
// Clear the packet descriptor and copy the command data if available
memset(packet->desc, 0, sizeof(packet->desc));
if (data != NULL) {
memcpy(packet->data, data, data_length);
}
// Fill frame type
packet->length = data_length & 0xFFF;
packet->command = (uint16_t)command;
// Fill the packet identifier
packet->unused[1] = custom_host_desc;
return sl_si91x_driver_send_command_packet(command, command_type, buffer, wait_period, sdk_context, data_buffer);
}
sl_status_t sl_si91x_driver_send_command(uint32_t command,
sl_si91x_command_type_t command_type,
const void *data,
uint32_t data_length,
sl_si91x_wait_period_t wait_period,
void *sdk_context,
sl_wifi_buffer_t **data_buffer)
{
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
sl_status_t status;
// Check if the queue type is within valid range
if (command_type >= SI91X_CMD_MAX) {
return SL_STATUS_INVALID_INDEX;
}
// Allocate a buffer for the command with appropriate size
status = sli_si91x_allocate_command_buffer(&buffer,
(void **)&packet,
sizeof(sl_si91x_packet_t) + data_length,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
// Clear the packet descriptor and copy the command data if available
memset(packet->desc, 0, sizeof(packet->desc));
if (data != NULL) {
memcpy(packet->data, data, data_length);
}
// Set SLI_SI91X_FEAT_FW_UPDATE_NEW_CODE in the feature bit map to retrieve the latest firmware result codes
if (command == RSI_COMMON_REQ_OPERMODE) {
sl_si91x_boot_configuration_t *boot_configuration = (sl_si91x_boot_configuration_t *)packet->data;
boot_configuration->feature_bit_map |= SLI_SI91X_FEAT_FW_UPDATE_NEW_CODE;
}
// Fill frame type
packet->length = data_length & 0xFFF;
packet->command = (uint16_t)command;
return sl_si91x_driver_send_command_packet(command, command_type, buffer, wait_period, sdk_context, data_buffer);
}
#ifdef SL_SI91X_SIDE_BAND_CRYPTO
sl_status_t sl_si91x_driver_send_side_band_crypto(uint32_t command,
const void *data,
uint32_t data_length,
sl_si91x_wait_period_t wait_period)
{
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
uint32_t result;
sl_status_t status = SL_STATUS_OK;
// Allocate a buffer for the command with appropriate size
status = sli_si91x_allocate_command_buffer(&buffer, (void **)&packet, sizeof(sl_si91x_packet_t) + data_length, 1000);
VERIFY_STATUS_AND_RETURN(status);
// Clear the packet descriptor and copy the command data if available
memset(packet->desc, 0, sizeof(packet->desc));
if (data != NULL) {
memcpy(packet->data, data, data_length);
}
// Fill frame type
packet->length = data_length & 0xFFF;
packet->command = command;
// Acquire Mutex
osMutexAcquire(side_band_crypto_mutex, 0xFFFFFFFFUL);
// fill crypto desc
crypto_desc[0].addr = (uint32_t)packet->desc;
crypto_desc[0].length = SL_HOST_DESC_LEN;
crypto_desc[1].addr = (uint32_t)packet->data;
crypto_desc[1].length = SL_CRYPTO_PKT_LEN;
//! Enter Critical Section
__disable_irq();
sli_si91x_raise_side_band_interrupt_to_ta();
//! Exit Critical Section
__enable_irq();
result =
osEventFlagsWait(ta_events, SIDE_BAND_DONE, (osFlagsWaitAny), (wait_period & ~SL_SI91X_WAIT_FOR_RESPONSE_BIT));
if (result == (uint32_t)osErrorTimeout || result == (uint32_t)osErrorResource) {
osMutexRelease(side_band_crypto_mutex);
sl_si91x_host_free_buffer(buffer);
return SL_STATUS_TIMEOUT;
}
status =
(((uint8_t *)crypto_desc[0].addr)[12] + (((uint8_t *)crypto_desc[0].addr)[13] << 8)); // Extract the frame status
// Release Mutex
osMutexRelease(side_band_crypto_mutex);
sl_si91x_host_free_buffer(buffer);
return status;
}
#endif
sl_status_t sl_si91x_driver_send_bt_command(rsi_wlan_cmd_request_t command,
sl_si91x_command_type_t command_type,
sl_wifi_buffer_t *data,
uint8_t sync_command)
{
sl_si91x_wait_period_t wait_period = SL_SI91X_RETURN_IMMEDIATELY;
// Check if the queue type is within valid range
if (command_type >= SI91X_CMD_MAX) {
return SL_STATUS_INVALID_INDEX;
}
if (sync_command) {
return sl_si91x_driver_send_command_packet(command, command_type, data, wait_period, NULL, NULL);
} else {
return sl_si91x_driver_send_async_command(command, command_type, data, 0);
}
}
sl_status_t sl_si91x_driver_wait_for_response(rsi_wlan_cmd_request_t command, sl_si91x_wait_period_t wait_period)
{
UNUSED_PARAMETER(command);
UNUSED_PARAMETER(wait_period);
#ifdef SI91x_ENABLE_WAIT_ON_RESULTS
// Wait for WLAN response events with a specified timeout
uint32_t events =
sli_si91x_wait_for_event(NCP_HOST_WLAN_RESPONSE_EVENT, (wait_period & ~SL_SI91X_WAIT_FOR_RESPONSE_BIT));
sli_si91x_clear_event(NCP_HOST_WLAN_RESPONSE_EVENT);
//TODO: Change error handling from event based to response
if (events & NCP_HOST_WLAN_RESPONSE_EVENT) {
return convert_and_save_firmware_status(si91x_frame_error_status);
} else if (events == 0) {
return SL_STATUS_TIMEOUT;
}
#endif
return SL_STATUS_NOT_SUPPORTED;
}
sl_status_t sli_si91x_driver_wait_for_response_packet(sl_si91x_buffer_queue_t *queue,
osEventFlagsId_t event_flag,
uint32_t event_mask,
uint16_t packet_id,
sl_si91x_wait_period_t wait_period,
sl_wifi_buffer_t **packet_buffer)
{
// Verify that packet_buffer is a valid pointer, return error if invalid
SL_VERIFY_POINTER_OR_RETURN(packet_buffer, SL_STATUS_INVALID_PARAMETER);
// Variables to store event flags, start time, and elapsed time
uint32_t events = 0;
uint32_t start_time = osKernelGetTickCount(); // Capture the start time of the wait period
uint32_t elapsed_time = 0; // Elapsed time tracker
sl_wifi_buffer_t *buffer;
do {
// Wait for event flag(s) to be set within the specified wait period.
// This blocks the thread until any event in the mask is set or a timeout occurs.
events = osEventFlagsWait(event_flag, event_mask, (osFlagsWaitAny | osFlagsNoClear), (wait_period - elapsed_time));
// If the event wait times out or resources are unavailable, return timeout status
if (events == (uint32_t)osErrorTimeout || events == (uint32_t)osErrorResource) {
return SL_STATUS_TIMEOUT;
}
// Log the event and queue details (for debugging purposes)
SL_DEBUG_LOG("Event: %u, queue %u\n", events, queue);
// Traverse the queue to check if the packet with the desired packet_id is at the head.
// Introduce a delay if the head of the queue packet doesn't belong to the current thread.
// This allows other threads to process the packet at the head.
do {
buffer = queue->head; // Peek at the head of the queue
} while ((buffer != NULL) && (buffer->id != packet_id)
&& osDelay(1) == 0); // Delay to yield if packet_id does not match
// Update the elapsed time since the start of the wait
elapsed_time = sl_si91x_host_elapsed_time(start_time);
} while (buffer == NULL || (buffer->id != packet_id)); // Loop until the correct packet is found or timeout occurs
// Remove the identified packet from the queue
sli_si91x_pop_from_buffer_queue(queue, &buffer);
// Assign the identified packet to packet_buffer
*packet_buffer = buffer;
// Enter atomic section to ensure thread safety while clearing the event flag
CORE_irqState_t state = CORE_EnterAtomic();
// If the queue is empty after popping the packet, clear the event flag to avoid unnecessary waits
if (queue->head == NULL) {
osEventFlagsClear(event_flag, event_mask);
}
CORE_ExitAtomic(state); // Exit atomic section
return SL_STATUS_OK; // Return success status
}
sl_status_t sl_si91x_driver_send_command_packet(uint32_t command,
sl_si91x_command_type_t command_type,
sl_wifi_buffer_t *buffer,
sl_si91x_wait_period_t wait_period,
void *sdk_context,
sl_wifi_buffer_t **data_buffer)
{
uint16_t firmware_status;
sli_si91x_queue_packet_t *node = NULL;
sl_status_t status;
sl_wifi_buffer_t *packet;
sl_wifi_buffer_t *response;
uint8_t flags = 0;
uint16_t data_length = 0;
// sl_si91x_driver_context_t context = { 0 };
sl_si91x_wait_period_t wait_time = 0;
static uint8_t command_packet_id = 0;
// Allocate a command packet and set flags based on the command type
status = sli_si91x_allocate_command_buffer(&packet,
(void **)&node,
sizeof(sli_si91x_queue_packet_t),
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
if (status != SL_STATUS_OK) {
sl_si91x_host_free_buffer(buffer);
return status;
}
#ifdef RSI_CHIP_MFG_EN
// WLAN soc frequency
if (command == RSI_BOOTUP_PARAMS) {
host_desc[14] = RSI_SOC_FREQ;
}
#endif
// Check the wait_period to determine the flags for packet handling
if (wait_period == SL_SI91X_RETURN_IMMEDIATELY) {
// If wait_period indicates an immediate return, set flags to 0
flags = 0;
} else {
// If not an immediate return, set the SI91X_PACKET_RESPONSE_STATUS flag
flags |= SI91X_PACKET_RESPONSE_STATUS;
// Additionally, set the SI91X_PACKET_RESPONSE_PACKET flag if the SL_SI91X_WAIT_FOR_RESPONSE_BIT is set in wait_period
if (data_buffer != NULL) {
flags |= ((wait_period & SL_SI91X_WAIT_FOR_RESPONSE_BIT) ? SI91X_PACKET_RESPONSE_PACKET : 0);
}
}
// Check the command type and set the flags accordingly
switch (command) {
case RSI_COMMON_REQ_PWRMODE:
case RSI_COMMON_REQ_OPERMODE:
case RSI_COMMON_REQ_SOFT_RESET:
flags |= SI91X_PACKET_GLOBAL_QUEUE_BLOCK;
break;
default:
break;
}
// Set various properties of the node representing the command packet
node->host_packet = buffer;
node->firmware_queue_id = firmware_queue_id[command_type];
node->command_type = command_type;
node->flags = flags;
node->sdk_context = sdk_context;
// Configure the context for packet handling
// context.packet = node;
// context.payload = &(queue_packet_id[command_type]);
if (flags != SI91X_PACKET_WITH_ASYNC_RESPONSE) {
node->command_tickcount = osKernelGetTickCount();
// Calculate the wait time based on wait_period
if ((wait_period & SL_SI91X_WAIT_FOR_EVER) == SL_SI91X_WAIT_FOR_EVER) {
node->command_timeout = osWaitForever;
} else {
node->command_timeout = (wait_period & ~SL_SI91X_WAIT_FOR_RESPONSE_BIT);
}
}
//! Enter Critical Section
CORE_irqState_t state = CORE_EnterAtomic();
const uint8_t this_packet_id = command_packet_id;
command_packet_id++;
buffer->id = this_packet_id;
packet->id = this_packet_id;
packet->node.node = NULL;
sli_si91x_append_to_buffer_queue(&cmd_queues[command_type].tx_queue, packet);
tx_command_queues_status |= SL_SI91X_TX_PENDING_FLAG(command_type);
sl_si91x_host_set_bus_event(SL_SI91X_TX_PENDING_FLAG(command_type));
CORE_ExitAtomic(state);
// Check if the command should return immediately or wait for a response
if (wait_period == SL_SI91X_RETURN_IMMEDIATELY) {
return SL_STATUS_IN_PROGRESS;
}
// Calculate the wait time based on wait_period
if ((wait_period & SL_SI91X_WAIT_FOR_EVER) == SL_SI91X_WAIT_FOR_EVER) {
wait_time = osWaitForever;
} else {
wait_time = (wait_period & ~SL_SI91X_WAIT_FOR_RESPONSE_BIT);
}
// Wait for a response packet and handle it
status = sli_si91x_driver_wait_for_response_packet(&cmd_queues[command_type].rx_queue,
si91x_events,
SL_SI91X_RESPONSE_FLAG(command_type),
this_packet_id,
wait_time,
&response);
// Check if the status is SL_STATUS_TIMEOUT, indicating a timeout has occurred
if (status == SL_STATUS_TIMEOUT) {
// Declare a temporary packet pointer to hold the packet to be removed
sl_wifi_buffer_t *temp_packet;
sl_status_t temp_status = sli_si91x_remove_buffer_from_queue_by_comparator(&cmd_queues[command_type].tx_queue,
&this_packet_id,
si91x_packet_identification_function,
&temp_packet);
// Check if the packet removal was successful
if (temp_status == SL_STATUS_OK) {
// Retrieve the actual packet node data from the removed buffer
sli_si91x_queue_packet_t *temp_node = sl_si91x_host_get_buffer_data(temp_packet, 0, NULL);
// Free the host packet memory associated with the node (TX packet memory)
sl_si91x_host_free_buffer(temp_node->host_packet);
// Free the temporary buffer memory that held the packet
sl_si91x_host_free_buffer(temp_packet);
}
}
VERIFY_STATUS_AND_RETURN(status);
// Process the response packet and return the firmware status
node = (sli_si91x_queue_packet_t *)sl_si91x_host_get_buffer_data(response, 0, &data_length);
firmware_status = node->frame_status;
// If a data_buffer is provided, set it to the host_packet
if (NULL != data_buffer) {
*data_buffer = node->host_packet;
}
// If the response packet flag is set, free the host_packet buffer
else if (SI91X_PACKET_RESPONSE_PACKET == (node->flags & SI91X_PACKET_RESPONSE_PACKET)) {
sl_si91x_host_free_buffer(node->host_packet);
}
// Free the response buffer and return the firmware status
sl_si91x_host_free_buffer(response);
return convert_and_save_firmware_status(firmware_status);
}
static sl_status_t sl_si91x_driver_send_data_packet(sl_wifi_buffer_t *buffer, uint32_t wait_time)
{
UNUSED_PARAMETER(wait_time);
sli_si91x_append_to_buffer_queue(&sli_tx_data_queue, buffer);
CORE_irqState_t state = CORE_EnterAtomic();
tx_generic_socket_data_queues_status |= SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT;
sl_si91x_host_set_bus_event(SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT);
CORE_ExitAtomic(state);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_driver_send_async_command(uint32_t command,
sl_si91x_command_type_t command_type,
void *data,
uint32_t data_length)
{
sli_si91x_queue_packet_t *node = NULL;
sl_status_t return_status;
// sl_si91x_driver_context_t context = { 0 };
sl_wifi_buffer_t *raw_rx_buffer;
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *raw_rx_packet;
sl_status_t status;
if (command_type == SI91X_BT_CMD) {
// BLE packet is created in upper layer, no allocations required here.
raw_rx_buffer = (sl_wifi_buffer_t *)data;
} else {
status = sli_si91x_allocate_command_buffer(&raw_rx_buffer,
(void **)&raw_rx_packet,
sizeof(sl_si91x_packet_t) + data_length,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
memset(raw_rx_packet->desc, 0, sizeof(raw_rx_packet->desc));
if (data != NULL) {
memcpy(raw_rx_packet->data, data, data_length);
}
// Fill frame type
raw_rx_packet->length = data_length & 0xFFF;
raw_rx_packet->command = (uint16_t)command;
}
return_status = sli_si91x_allocate_command_buffer(&buffer,
(void **)&node,
sizeof(sli_si91x_queue_packet_t),
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
if (return_status != SL_STATUS_OK) {
sl_si91x_host_free_buffer(raw_rx_buffer);
return return_status;
}
#ifdef RSI_CHIP_MFG_EN
// WLAN soc frequency
if (command == RSI_BOOTUP_PARAMS) {
host_desc[14] = RSI_SOC_FREQ;
}
#endif
// Configure the node representing the command packet
node->host_packet = raw_rx_buffer;
node->firmware_queue_id = firmware_queue_id[command_type];
node->command_type = command_type;
node->sdk_context = NULL;
node->flags = SI91X_PACKET_WITH_ASYNC_RESPONSE;
CORE_irqState_t irqState = CORE_EnterAtomic();
buffer->id = 0; // Does not use packet ID as async packets do not have a matching response
sli_si91x_append_to_buffer_queue(&cmd_queues[command_type].tx_queue, buffer);
tx_command_queues_status |= SL_SI91X_TX_PENDING_FLAG(command_type);
sl_si91x_host_set_bus_event(SL_SI91X_TX_PENDING_FLAG(command_type));
CORE_ExitAtomic(irqState);
return SL_STATUS_OK;
}
/*
* Verifies that the device has booted successfully.
* @return SL_STATUS_OK if verification successful
* otherwise RSI_ERROR_WAITING_FOR_BOARD_READY, RSI_ERROR_BOOTUP_OPTIONS_NOT_SAVED, RSI_ERROR_BOOTUP_OPTIONS_CHECKSUM_FAIL
*/
sl_status_t sli_verify_device_boot(uint32_t *rom_version)
{
sl_status_t status;
uint8_t value[2] = { 0, 0 };
// Read a memory register to check if it's valid
status = sl_si91x_bus_read_memory(RSI_HOST_INTF_REG_OUT, 2, &value[0]);
VERIFY_STATUS(status);
// Verify register read was valid
if (value[1] != SLI_WIFI_REGISTER_VALID) {
return SL_STATUS_WAITING_FOR_BOARD_READY;
}
// Verify register value
if (value[0] == RSI_BOOTUP_OPTIONS_LAST_CONFIG_NOT_SAVED) {
return SL_STATUS_BOOTUP_OPTIONS_NOT_SAVED;
} else if (value[0] == RSI_BOOTUP_OPTIONS_CHECKSUM_FAIL) {
return SL_STATUS_BOOTUP_OPTIONS_CHECKSUM_FAILURE;
}
#if RSI_BOOTLOADER_VERSION_CHECK
else if (value[0] == RSI_BOOTLOADER_VERSION) {
} else {
return SL_STATUS_BOOTLOADER_VERSION_MISMATCH;
}
#endif
// Extract ROM version info
if (value[0] == RSI_BOOTLOADER_VERSION_1P0) {
*rom_version = RSI_ROM_VERSION_1P0;
} else if (value[0] == RSI_BOOTLOADER_VERSION_1P1) {
*rom_version = RSI_ROM_VERSION_1P1;
}
return SL_STATUS_OK;
}
/**************************************************************************/ /**
* @brief Allocate a buffer for the Wi-Fi driver
*
* @param buffer
* @param buffer_size is the size of the buffer to allocate
* @param wait_duration_ms is the duration before returning SL_TIMEOUT
* @return SL_STATUS_OK if the values are retrieved correctly,
* SL_TIMEOUT if the buffer is not allocated in time, SL_ERROR otherwise
*****************************************************************************/
sl_status_t sli_si91x_allocate_command_buffer(sl_wifi_buffer_t **host_buffer,
void **buffer,
uint32_t requested_buffer_size,
uint32_t wait_duration_ms)
{
// Allocate a buffer from the SI91x host for WLAN control messages
sl_status_t status =
sl_si91x_host_allocate_buffer(host_buffer, SL_WIFI_CONTROL_BUFFER, requested_buffer_size, wait_duration_ms);
VERIFY_STATUS_AND_RETURN(status);
uint16_t temp;
// Get a pointer to the allocated buffer's data area
*buffer = sl_si91x_host_get_buffer_data(*host_buffer, 0, &temp);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_allocate_data_buffer(sl_wifi_buffer_t **host_buffer,
void **buffer,
uint32_t data_size,
uint32_t wait_duration_ms)
{
// Allocate a buffer from the SI91x host for WLAN data transmission
sl_status_t status =
sl_si91x_host_allocate_buffer(host_buffer,
SL_WIFI_TX_FRAME_BUFFER,
sizeof(sl_si91x_packet_t) + sizeof(sli_si91x_socket_send_request_t) + data_size,
wait_duration_ms);
VERIFY_STATUS_AND_RETURN(status);
uint16_t temp;
// Get a pointer to the allocated buffer's data area
*buffer = sl_si91x_host_get_buffer_data(*host_buffer, 0, &temp);
return SL_STATUS_OK;
}
sl_status_t sli_wifi_select_option(const uint8_t configuration)
{
uint16_t boot_command = 0;
sl_status_t status = 0;
uint16_t read_value = 0;
// Write a boot command to initiate the option selection
status = sl_si91x_bus_write_memory(RSI_HOST_INTF_REG_OUT, 2, (uint8_t *)&boot_command);
VERIFY_STATUS_AND_RETURN(status);
if ((configuration == BURN_NWP_FW) || (configuration == BURN_M4_FW)) {
boot_command = RSI_HOST_INTERACT_REG_VALID_FW | configuration;
} else {
boot_command = RSI_HOST_INTERACT_REG_VALID | configuration;
}
if (configuration == BURN_M4_FW) {
boot_command |= M4_FW_IMAGE_NUMBER;
}
// Write the configuration to the SI91x host for option selection
status = sl_si91x_bus_write_memory(RSI_HOST_INTF_REG_IN, 2, (uint8_t *)&boot_command);
VERIFY_STATUS_AND_RETURN(status);
// Check for a specific response to ensure successful option selection
if ((configuration != LOAD_NWP_FW) && (configuration != LOAD_DEFAULT_NWP_FW_ACTIVE_LOW)) {
uint32_t timestamp = sl_si91x_host_get_timestamp();
while (sl_si91x_host_elapsed_time(timestamp) < 300) {
status = sl_si91x_bus_read_memory(RSI_HOST_INTF_REG_OUT, 2, (uint8_t *)&read_value);
VERIFY_STATUS_AND_RETURN(status);
if ((configuration == BURN_NWP_FW) || (configuration == BURN_M4_FW)) {
if (read_value == (RSI_HOST_INTERACT_REG_VALID | RSI_SEND_RPS_FILE)) {
return SL_STATUS_OK;
}
} else if (read_value == (RSI_HOST_INTERACT_REG_VALID | configuration)) {
return SL_STATUS_OK;
}
}
} else {
// Check up to 3 seconds for firmware load or upgrade status
uint32_t timestamp = sl_si91x_host_get_timestamp();
uint16_t default_nwp_fw_selected = 0;
while (sl_si91x_host_elapsed_time(timestamp) < 3000) {
status = sl_si91x_bus_read_memory(RSI_HOST_INTF_REG_OUT, 2, (uint8_t *)&read_value);
if (status != SL_STATUS_OK)
continue;
if ((read_value & 0xF000) == (RSI_HOST_INTERACT_REG_VALID_FW & 0xF000)) {
if ((read_value & 0xFF) == VALID_FIRMWARE_NOT_PRESENT) {
if (default_nwp_fw_selected == 0) {
boot_command = RSI_HOST_INTERACT_REG_VALID_FW | SELECT_DEFAULT_NWP_FW_IMAGE_NUMBER;
status = sl_si91x_bus_write_memory(RSI_HOST_INTF_REG_IN, 2, (uint8_t *)&boot_command);
if (status != SL_STATUS_OK) {
return status;
}
while (sl_si91x_host_elapsed_time(timestamp) < 2000) {
status = sl_si91x_bus_read_memory(RSI_HOST_INTF_REG_OUT, 2, (uint8_t *)&read_value);
if (status != SL_STATUS_OK)
continue;
if (read_value == (RSI_HOST_INTERACT_REG_VALID | SELECT_DEFAULT_NWP_FW_IMAGE_NUMBER)) {
break;
}
}
boot_command = RSI_HOST_INTERACT_REG_VALID_FW | configuration;
status = sl_si91x_bus_write_memory(RSI_HOST_INTF_REG_IN, 2, (uint8_t *)&boot_command);
if (status != SL_STATUS_OK) {
return status;
}
default_nwp_fw_selected = 1;
continue;
} else {
return SL_STATUS_VALID_FIRMWARE_NOT_PRESENT;
}
}
if ((read_value & 0xFF) == RSI_INVALID_OPTION) {
return SL_STATUS_INVALID_OPTION;
}
if ((read_value & 0xFF) == RSI_CHECKSUM_SUCCESS) {
return status;
}
}
}
}
return SL_STATUS_FW_LOAD_OR_UPGRADE_TIMEOUT;
}
sl_status_t sl_si91x_enable_radio(void)
{
uint8_t data = 1;
sl_status_t status = sl_si91x_driver_send_command(RSI_WLAN_REQ_RADIO,
SI91X_WLAN_CMD,
&data,
1,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_disable_radio(void)
{
uint8_t data = 0;
sl_status_t status = sl_si91x_driver_send_command(RSI_WLAN_REQ_RADIO,
SI91X_WLAN_CMD,
&data,
1,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_write_calibration_data(const si91x_calibration_data_t *data)
{
sl_status_t status = sl_si91x_driver_send_command(RSI_WLAN_REQ_CALIB_WRITE,
SI91X_WLAN_CMD,
data,
sizeof(si91x_calibration_data_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_wifi_set_certificate_index(uint8_t certificate_type,
uint8_t certificate_index,
const uint8_t *buffer,
uint32_t certificate_length)
{
uint32_t rem_len = 0;
uint16_t chunk_size = 0;
uint16_t data_size = 0;
uint8_t chunks_remaining = 0;
uint32_t offset = 0;
sl_status_t status = SL_STATUS_OK;
sl_si91x_req_set_certificate_t chunk_ptr = { 0 };
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
// Get the certificate chunk size
chunk_size = (SI91X_MAX_CERT_SEND_SIZE - sizeof(sl_si91x_cert_info_t));
// Get certificate length
rem_len = certificate_length;
do {
// Memset the PKT
memset(&chunk_ptr, 0, sizeof(sl_si91x_req_set_certificate_t));
// If certificate length is 0, erase certificate
if (rem_len == 0) {
// Mark Data Size
data_size = 0;
// More chunks to send
chunks_remaining = 0;
} else if (rem_len >= chunk_size) {
// Mark Data Size
data_size = chunk_size;
// More chunks to send
chunks_remaining = 1;
} else {
// Mark Data Size
data_size = (uint16_t)rem_len;
// More chunks to send
chunks_remaining = 0;
}
if ((data_size > 0) && (NULL != buffer)) {
// Copy the certificate chunk
memcpy(chunk_ptr.certificate, buffer + offset, data_size);
}
// Move the offset by chunk size
offset += data_size;
// Subtract the rem_len by the chunk size
rem_len -= data_size;
//Set the total length of certificate
memcpy(&chunk_ptr.cert_info.total_len, &certificate_length, sizeof(chunk_ptr.cert_info.total_len));
// Set the certificate type
chunk_ptr.cert_info.certificate_type = certificate_type;
// Set the certificate index
chunk_ptr.cert_info.certificate_inx = certificate_index;
// More chunks to send
chunk_ptr.cert_info.more_chunks = chunks_remaining;
// Set the length of the certificate chunk
chunk_ptr.cert_info.certificate_length = data_size;
// Send the driver command
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_SET_CERTIFICATE,
SI91X_WLAN_CMD,
&chunk_ptr,
(sizeof(sl_si91x_cert_info_t) + data_size),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
} while (rem_len > 0);
// Return status
return status;
}
sl_status_t sl_si91x_set_rtc_timer(const sl_si91x_module_rtc_time_t *timer)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
if ((timer->tm_sec > 59) || (timer->tm_min > 59) || (timer->tm_hour > 23)
|| ((timer->tm_mday < 1) || (timer->tm_mday > 31)) || (timer->tm_mon > 11)
|| ((timer->tm_wday < 1) || (timer->tm_wday > 7))) {
// Checking Invalid Parameters
return SL_STATUS_INVALID_PARAMETER;
}
// Send set RTC timer request
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_SET_RTC_TIMER,
SI91X_COMMON_CMD,
timer,
sizeof(sl_si91x_module_rtc_time_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_get_rtc_timer(sl_si91x_module_rtc_time_t *response)
{
sl_status_t status = SL_STATUS_OK;
sl_wifi_buffer_t *buffer = NULL;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_WIFI_ARGS_CHECK_NULL_POINTER(response);
// Send get RTC timer request
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_GET_RTC_TIMER,
SI91X_COMMON_CMD,
NULL,
0,
SL_SI91X_WAIT_FOR_RESPONSE(30000),
NULL,
&buffer);
if ((status != SL_STATUS_OK) && (buffer != NULL)) {
sl_si91x_host_free_buffer(buffer);
}
VERIFY_STATUS_AND_RETURN(status);
// Extract the RTC timer data from the response
const sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
memcpy(response, packet->data, sizeof(sl_si91x_module_rtc_time_t));
sl_si91x_host_free_buffer(buffer);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_set_device_region(sl_si91x_operation_mode_t operation_mode,
sl_si91x_band_mode_t band,
sl_si91x_region_code_t region_code)
{
sl_status_t status = SL_STATUS_OK;
switch (operation_mode) {
case SL_SI91X_CLIENT_MODE:
case SL_SI91X_ENTERPRISE_CLIENT_MODE:
case SL_SI91X_TRANSMIT_TEST_MODE:
case SL_SI91X_TRANSCEIVER_MODE: {
// For client and transmit test modes, send a command to set the region code
sl_si91x_set_region_request_t request = { 0 };
request.set_region_code_from_user_cmd = SET_REGION_CODE_FROM_USER;
request.region_code = (uint8_t)region_code;
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_SET_REGION,
SI91X_WLAN_CMD,
&request,
sizeof(sl_si91x_set_region_request_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
break;
}
case SL_SI91X_CONCURRENT_MODE:
case SL_SI91X_ACCESS_POINT_MODE: {
if (operation_mode == SL_SI91X_CONCURRENT_MODE) {
// For concurrent mode, send a command to set the region code
sl_si91x_set_region_request_t request = { 0 };
request.set_region_code_from_user_cmd = SET_REGION_CODE_FROM_USER;
request.region_code = (uint8_t)region_code;
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_SET_REGION,
SI91X_WLAN_CMD,
&request,
sizeof(sl_si91x_set_region_request_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
}
// For AP and concurrent modes, configure region-specific settings
sl_si91x_set_region_ap_request_t request = { 0 };
request.set_region_code_from_user_cmd = SET_REGION_CODE_FROM_USER;
// Configure region-specific settings based on the region code and band
switch (region_code) {
// Configure settings for different regions and bands
case DEFAULT_REGION:
case US: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_US_region_2_4GHZ_configurations;
} else {
request = default_US_region_5GHZ_configurations;
}
break;
}
case EU: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_EU_region_2_4GHZ_configurations;
} else {
request = default_EU_region_5GHZ_configurations;
}
break;
}
case JP: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_JP_region_2_4GHZ_configurations;
} else {
request = default_JP_region_5GHZ_configurations;
}
break;
}
case KR: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_KR_region_2_4GHZ_configurations;
} else {
request = default_KR_region_5GHZ_configurations;
}
break;
}
case SG: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_SG_region_2_4GHZ_configurations;
} else {
request = default_SG_region_5GHZ_configurations;
}
break;
}
case CN: {
if (band == SL_SI91X_WIFI_BAND_2_4GHZ) {
request = default_CN_region_2_4GHZ_configurations;
} else {
request = default_CN_region_5GHZ_configurations;
}
break;
}
default:
return SL_STATUS_NOT_SUPPORTED;
}
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_SET_REGION_AP,
SI91X_WLAN_CMD,
&request,
sizeof(sl_si91x_set_region_ap_request_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
break;
}
default:
break;
}
return status;
}
#ifdef SLI_SI91X_MCU_INTERFACE
sl_status_t sl_si91x_command_to_write_common_flash(uint32_t write_address,
const uint8_t *write_data,
uint16_t write_data_length,
uint8_t flash_sector_erase_enable)
{
// Check if write_data_length is non-zero
if (write_data_length == 0) {
return SL_STATUS_INVALID_PARAMETER;
}
sl_status_t status = SL_STATUS_OK;
sl_si91x_request_ta2m4_t ta_to_m4_request = { 0 };
uint32_t send_size = 0;
uint16_t remaining_length = write_data_length;
// If flash_sector_erase_enable is 1, Send request to NWP in chunks of 4k
if (flash_sector_erase_enable == 1) {
while (remaining_length > 0) {
// Calculate the chunk size, capped at 4k
size_t chunkSize = (remaining_length < FLASH_SECTOR_SIZE) ? remaining_length : FLASH_SECTOR_SIZE;
// Fill the request structure
memset(&ta_to_m4_request, 0, sizeof(sl_si91x_request_ta2m4_t));
ta_to_m4_request.sub_cmd = SL_SI91X_WRITE_TO_COMMON_FLASH;
ta_to_m4_request.addr = write_address;
ta_to_m4_request.input_buffer_length = (uint16_t)chunkSize;
ta_to_m4_request.flash_sector_erase_enable = flash_sector_erase_enable;
send_size = sizeof(sl_si91x_request_ta2m4_t);
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_TA_M4_COMMANDS,
SI91X_COMMON_CMD,
&ta_to_m4_request,
send_size,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
// Adjust write_address for the next chunk
write_address += chunkSize;
// Adjust remaining_length for the next chunk
remaining_length -= chunkSize;
}
}
else {
// Check if write_data pointer is valid
SL_VERIFY_POINTER_OR_RETURN(write_data, SL_STATUS_INVALID_PARAMETER);
// Write in chunks of MAX_CHUNK_SIZE for flash_sector_erase_enable != 1
while (write_data_length > 0) {
size_t chunkSize = (write_data_length < MAX_CHUNK_SIZE) ? write_data_length : MAX_CHUNK_SIZE;
// Fill the request structure
memset(&ta_to_m4_request, 0, sizeof(sl_si91x_request_ta2m4_t));
ta_to_m4_request.sub_cmd = SL_SI91X_WRITE_TO_COMMON_FLASH;
ta_to_m4_request.addr = write_address;
ta_to_m4_request.input_buffer_length = (uint16_t)chunkSize;
ta_to_m4_request.flash_sector_erase_enable = flash_sector_erase_enable;
// Copy write_data into the request structure
memcpy(&ta_to_m4_request.input_data, write_data, chunkSize);
// Calculate the send size and send the command to write to common flash
send_size = sizeof(sl_si91x_request_ta2m4_t) - MAX_CHUNK_SIZE + chunkSize;
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_TA_M4_COMMANDS,
SI91X_COMMON_CMD,
&ta_to_m4_request,
send_size,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
// Adjust pointers and counters
write_address += chunkSize;
write_data += chunkSize;
write_data_length -= chunkSize;
}
}
return status;
}
sl_status_t sl_si91x_command_to_read_common_flash(uint32_t read_address, size_t length, uint8_t *output_buffer)
{
// Check if output_buffer pointer is valid
SL_VERIFY_POINTER_OR_RETURN(output_buffer, SL_STATUS_INVALID_PARAMETER);
// Check if length is non-zero
if (length == 0) {
return SL_STATUS_INVALID_PARAMETER;
}
sl_status_t status = SL_STATUS_OK;
sl_wifi_buffer_t *buffer = NULL;
const sl_si91x_packet_t *packet = NULL;
while (length > 0) {
size_t chunkSize = (length < MAX_CHUNK_SIZE) ? length : MAX_CHUNK_SIZE;
sl_si91x_read_flash_request_t m4_to_ta_read_request = { 0 };
memset(&m4_to_ta_read_request, 0, sizeof(sl_si91x_read_flash_request_t));
m4_to_ta_read_request.sub_cmd = SL_SI91X_READ_FROM_COMMON_FLASH;
m4_to_ta_read_request.nwp_address = read_address;
m4_to_ta_read_request.output_buffer_length = (uint16_t)chunkSize;
uint32_t send_size = sizeof(sl_si91x_read_flash_request_t);
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_TA_M4_COMMANDS,
SI91X_COMMON_CMD,
&m4_to_ta_read_request,
send_size,
SL_SI91X_WAIT_FOR_RESPONSE(32000),
NULL,
&buffer);
if (status != SL_STATUS_OK) {
if (buffer != NULL)
sl_si91x_host_free_buffer(buffer);
return status;
}
VERIFY_STATUS_AND_RETURN(status);
packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
memcpy(output_buffer, packet->data, packet->length);
sl_si91x_host_free_buffer(buffer);
// Adjust pointers and counters
read_address += chunkSize;
output_buffer += chunkSize;
length -= chunkSize;
}
return status;
}
sl_status_t sl_si91x_m4_ta_secure_handshake(uint8_t sub_cmd_type,
uint8_t input_len,
const uint8_t *input_data,
uint8_t output_len,
const uint8_t *output_data)
{
UNUSED_PARAMETER(output_len);
UNUSED_PARAMETER(output_data);
sl_si91x_ta_m4_handshake_parameters_t *handshake_request = NULL;
sl_status_t status = SL_STATUS_OK;
SL_VERIFY_POINTER_OR_RETURN(input_data, SL_STATUS_INVALID_PARAMETER);
handshake_request = malloc(sizeof(sl_si91x_ta_m4_handshake_parameters_t) + input_len);
SL_VERIFY_POINTER_OR_RETURN(handshake_request, SL_STATUS_ALLOCATION_FAILED);
memset(handshake_request, 0, sizeof(sl_si91x_ta_m4_handshake_parameters_t) + input_len);
handshake_request->sub_cmd = sub_cmd_type;
handshake_request->input_data_size = input_len;
memcpy(handshake_request->input_data, input_data, input_len);
// Send the secure handshake command to the M4 core
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_TA_M4_COMMANDS,
SI91X_COMMON_CMD,
handshake_request,
sizeof(sl_si91x_ta_m4_handshake_parameters_t) + input_len,
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
free(handshake_request);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
// Perform a soft reset
static sl_status_t sl_si91x_soft_reset(void)
{
sl_status_t status;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_SOFT_RESET,
SI91X_COMMON_CMD,
NULL,
0,
SL_SI91X_WAIT_FOR_RESPONSE(30000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
#endif
sl_status_t sl_si91x_assert()
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
status =
sl_si91x_driver_send_command(RSI_COMMON_REQ_ASSERT, SI91X_WLAN_CMD, NULL, 0, SL_SI91X_WAIT_FOR(30000), NULL, NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_get_ram_log(uint32_t address, uint32_t length)
{
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
sl_status_t status = SL_STATUS_OK;
sl_si91x_ram_dump_t ram = { .address = address, .length = length };
// Check for invalid length parameter
if (length == 0) {
return SL_STATUS_INVALID_PARAMETER;
}
// Send RAM log request
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_GET_RAM_DUMP,
SI91X_COMMON_CMD,
&ram,
sizeof(sl_si91x_ram_dump_t),
SL_SI91X_WAIT_FOR(31000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_transmit_test_start(const sl_si91x_request_tx_test_info_t *tx_test_info)
{
sl_status_t status = SL_STATUS_OK;
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_TX_TEST_MODE,
SI91X_WLAN_CMD,
tx_test_info,
sizeof(sl_si91x_request_tx_test_info_t),
SL_SI91X_WAIT_FOR(30100),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_transmit_test_stop(void)
{
sl_status_t status = SL_STATUS_OK;
sl_si91x_request_tx_test_info_t tx_test_info = { 0 };
tx_test_info.enable = 0;
// Send the transmit test stop command
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_TX_TEST_MODE,
SI91X_WLAN_CMD,
&tx_test_info,
sizeof(sl_si91x_request_tx_test_info_t),
SL_SI91X_WAIT_FOR(30100),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_si91x_operation_mode_t get_opermode(void)
{
return initialized_opermode;
}
sl_status_t sl_si91x_calibration_write(sl_si91x_calibration_write_t calib_write)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_CALIB_WRITE,
SI91X_WLAN_CMD,
&calib_write,
sizeof(sl_si91x_calibration_write_t),
SL_SI91X_WAIT_FOR(30000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_calibration_read(sl_si91x_calibration_read_t target, sl_si91x_calibration_read_t *calibration_read)
{
sl_wifi_buffer_t *buffer = NULL;
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(calibration_read, SL_STATUS_NULL_POINTER);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_CALIB_READ,
SI91X_WLAN_CMD,
&target,
sizeof(sl_si91x_calibration_read_t),
SL_SI91X_WAIT_FOR_RESPONSE(30100),
NULL,
&buffer);
if ((status != SL_STATUS_OK) && (buffer != NULL)) {
sl_si91x_host_free_buffer(buffer);
return status;
}
const sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
memcpy(calibration_read, packet->data, sizeof(sl_si91x_calibration_read_t));
sl_si91x_host_free_buffer(buffer);
return status;
}
sl_status_t sl_si91x_frequency_offset(const sl_si91x_freq_offset_t *frequency_calibration)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(frequency_calibration, SL_STATUS_NULL_POINTER);
// Send the frequency offset calibration command to the SI91x WLAN module
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_FREQ_OFFSET,
SI91X_WLAN_CMD,
frequency_calibration,
sizeof(sl_si91x_freq_offset_t),
SL_SI91X_WAIT_FOR_RESPONSE(35000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_evm_offset(const sl_si91x_evm_offset_t *evm_offset)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(evm_offset, SL_STATUS_NULL_POINTER);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_EVM_OFFSET,
SI91X_WLAN_CMD,
evm_offset,
sizeof(sl_si91x_evm_offset_t),
SL_SI91X_WAIT_FOR_RESPONSE(35000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_evm_write(const sl_si91x_evm_write_t *evm_write)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(evm_write, SL_STATUS_NULL_POINTER);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_EVM_WRITE,
SI91X_WLAN_CMD,
evm_write,
sizeof(sl_si91x_evm_write_t),
SL_SI91X_WAIT_FOR_RESPONSE(35000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return SL_STATUS_OK;
}
sl_status_t sl_si91x_dpd_calibration(const sl_si91x_get_dpd_calib_data_t *dpd_calib_data)
{
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(dpd_calib_data, SL_STATUS_NULL_POINTER);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_GET_DPD_DATA,
SI91X_WLAN_CMD,
dpd_calib_data,
sizeof(sl_si91x_get_dpd_calib_data_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}
sl_status_t sl_si91x_efuse_read(const sl_si91x_efuse_read_t *efuse_read, uint8_t *efuse_read_buf)
{
sl_wifi_buffer_t *buffer = NULL;
sl_status_t status = SL_STATUS_OK;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_VERIFY_POINTER_OR_RETURN(efuse_read, SL_STATUS_NULL_POINTER);
SL_VERIFY_POINTER_OR_RETURN(efuse_read_buf, SL_STATUS_NULL_POINTER);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_EFUSE_READ,
SI91X_WLAN_CMD,
efuse_read,
sizeof(sl_si91x_efuse_read_t),
SL_SI91X_WAIT_FOR_RESPONSE(30100),
NULL,
&buffer);
if ((status != SL_STATUS_OK) && (buffer != NULL)) {
sl_si91x_host_free_buffer(buffer);
return status;
}
const sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
memcpy(efuse_read_buf, packet->data, efuse_read->efuse_read_data_len);
sl_si91x_host_free_buffer(buffer);
return status;
}
sl_status_t sl_si91x_set_join_configuration(sl_wifi_interface_t interface, uint8_t join_feature_bitmap)
{
// Determine whether the configuration is for the client or AP interface
if (interface & SL_WIFI_CLIENT_INTERFACE) {
client_join_feature_bitmap = join_feature_bitmap;
} else if (interface & SL_WIFI_AP_INTERFACE) {
ap_join_feature_bitmap = join_feature_bitmap;
} else {
return SL_STATUS_FAIL;
}
return SL_STATUS_OK;
}
sl_status_t sl_si91x_get_join_configuration(sl_wifi_interface_t interface, uint8_t *join_feature_bitmap)
{
SL_WIFI_ARGS_CHECK_NULL_POINTER(join_feature_bitmap);
// Determine whether to retrieve the configuration for the client or AP interface
if (interface & SL_WIFI_CLIENT_INTERFACE) {
*join_feature_bitmap = client_join_feature_bitmap;
} else if (interface & SL_WIFI_AP_INTERFACE) {
*join_feature_bitmap = ap_join_feature_bitmap;
} else {
return SL_STATUS_WIFI_UNKNOWN_INTERFACE;
}
return SL_STATUS_OK;
}
void sl_si91x_set_listen_interval(uint32_t listen_interval)
{
client_listen_interval = listen_interval;
return;
}
uint32_t sl_si91x_get_listen_interval(void)
{
return client_listen_interval;
}
void sl_si91x_set_timeout(const sl_si91x_timeout_t *timeout_config)
{
memcpy(&timeout_glbl, timeout_config, sizeof(sl_si91x_timeout_t));
return;
}
sl_status_t sl_si91x_configure_timeout(sl_si91x_timeout_type_t timeout_type, uint16_t timeout_value)
{
sl_status_t status = SL_STATUS_OK;
sl_si91x_request_timeout_t timeout_request = { 0 };
if (timeout_type > SL_SI91X_CHANNEL_PASSIVE_SCAN_TIMEOUT) {
return SL_STATUS_INVALID_PARAMETER;
}
timeout_request.timeout_bitmap = BIT(timeout_type);
timeout_request.timeout_value = timeout_value;
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_TIMEOUT,
SI91X_WLAN_CMD,
&timeout_request,
sizeof(sl_si91x_request_timeout_t),
SL_SI91X_WAIT_FOR(30100),
NULL,
NULL);
return status;
}
uint16_t get_seq_ctrl(uint8_t is_qos)
{
static uint16_t qos_pkt_count = 0;
static uint16_t non_qos_pkt_count = 0;
if (qos_pkt_count > 4095)
qos_pkt_count = 0;
if (non_qos_pkt_count > 4095)
non_qos_pkt_count = 0;
return is_qos ? qos_pkt_count++ : non_qos_pkt_count++;
}
int32_t encapsulate_tx_data_packet(sl_wifi_transceiver_tx_data_control_t *control,
uint8_t *pkt_data,
uint32_t mac_hdr_len)
{
uint16_t seq_ctrl = 0;
uint16_t *frame_ctrl;
uint32_t qos_ctrl_off = MAC80211_HDR_MIN_LEN;
SL_VERIFY_POINTER_OR_RETURN(control, SL_STATUS_NULL_POINTER);
if (IS_MAC_ZERO(control->addr1)) {
return SL_STATUS_TRANSCEIVER_INVALID_MAC_ADDRESS;
}
/* Auto-rate is unsupported if Peer DS feature in MAC layer is disabled */
if ((!IS_PEER_DS_SUPPORT_ENABLED(feature_bit_map)) && !IS_FIXED_DATA_RATE(control->ctrl_flags)) {
return SL_STATUS_TRANSCEIVER_INVALID_DATA_RATE;
}
/* Ignore QoS flag for bcast/mcast frames */
if (IS_BCAST_MCAST_MAC(control->addr1[0])) {
control->ctrl_flags &= ~TX_DATA_CTRL_FLAG_QOS_BIT;
}
if ((IS_QOS_PKT(control->ctrl_flags) && !IS_BCAST_MCAST_MAC(control->addr1[0])) && (control->priority > 3)) {
return SL_STATUS_TRANSCEIVER_INVALID_QOS_PRIORITY;
}
if (IS_4ADDR(control->ctrl_flags)) {
qos_ctrl_off += MAC80211_HDR_ADDR4_LEN;
}
memset(pkt_data, 0, mac_hdr_len);
/* Add frame control (2 bytes) */
frame_ctrl = (uint16_t *)&pkt_data[0];
*frame_ctrl |= FC_TYPE_DATA;
if (IS_4ADDR(control->ctrl_flags)) {
*frame_ctrl |= FC_TO_DS;
*frame_ctrl |= FC_FROM_DS;
} else {
*frame_ctrl |= IS_TODS(control->ctrl_flags) ? FC_TO_DS : 0;
*frame_ctrl |= IS_FROMDS(control->ctrl_flags) ? FC_FROM_DS : 0;
}
/* Add Addr1, Addr2, Addr3 (18 bytes) */
memcpy(&pkt_data[4], control->addr1, 6);
memcpy(&pkt_data[10], control->addr2, 6);
memcpy(&pkt_data[16], control->addr3, 6);
if (!IS_PEER_DS_SUPPORT_ENABLED(feature_bit_map)) {
seq_ctrl = (uint16_t)(get_seq_ctrl(IS_QOS_PKT(control->ctrl_flags)) << 4);
memcpy(&pkt_data[22], &seq_ctrl, 2);
}
/* Add Addr4 optionally based on ctrl_flag (6 bytes) */
if (IS_4ADDR(control->ctrl_flags)) {
memcpy(&pkt_data[24], control->addr4, 6); /* sa */
}
/* Add QoS control optionally based on ctrl_flag (2 bytes) */
if (IS_QOS_PKT(control->ctrl_flags) && !IS_BCAST_MCAST_MAC(control->addr1[0])) {
*frame_ctrl |= FC_SUBTYPE_QOS_DATA;
pkt_data[qos_ctrl_off] = WME_AC_TO_TID(control->priority);
}
return SL_STATUS_OK;
}
sl_status_t sl_si91x_driver_send_transceiver_data(sl_wifi_transceiver_tx_data_control_t *control,
const uint8_t *payload,
uint16_t payload_len,
uint32_t wait_time)
{
sl_wifi_buffer_t *buffer;
sl_si91x_packet_t *packet;
sl_status_t status = SL_STATUS_OK;
uint8_t *pkt_offset;
uint8_t ext_desc_size;
uint8_t *host_desc;
uint32_t mac_hdr_len = MAC80211_HDR_MIN_LEN;
if (IS_QOS_PKT(control->ctrl_flags) && !IS_BCAST_MCAST_MAC(control->addr1[0])) {
mac_hdr_len += MAC80211_HDR_QOS_CTRL_LEN;
}
if (IS_4ADDR(control->ctrl_flags)) {
mac_hdr_len += MAC80211_HDR_ADDR4_LEN;
}
ext_desc_size = TRANSCEIVER_TX_DATA_EXT_DESC_SIZE;
// Allocate a data buffer with space for the data and metadata
status = sl_si91x_allocate_data_buffer(&buffer,
(void **)&packet,
sizeof(sl_si91x_packet_t) + ext_desc_size + mac_hdr_len + payload_len,
SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
VERIFY_STATUS_AND_RETURN(status);
// If the packet is not allocated successfully, return an allocation failed error
if (packet == NULL) {
return SL_STATUS_ALLOCATION_FAILED;
}
pkt_offset = packet->data + ext_desc_size;
status = encapsulate_tx_data_packet(control, pkt_offset, mac_hdr_len);
if (status != SL_STATUS_OK) {
sl_si91x_host_free_buffer(buffer);
return status;
}
memcpy(pkt_offset + mac_hdr_len, payload, payload_len);
#ifdef TX_RX_FRAME_DUMP_BYTE_COUNT
print_80211_packet(pkt_offset, mac_hdr_len + payload_len, TX_RX_FRAME_DUMP_BYTE_COUNT);
#endif
// Clear the packet descriptor and copy the command data if available
memset(packet->desc, 0, sizeof(packet->desc));
// Fill length in first 2 host_desc bytes
packet->length = (ext_desc_size + mac_hdr_len + payload_len) & 0xFFF;
// Fill packet type
host_desc = packet->desc;
host_desc[2] = 0x01; //! Frame Type
if (IS_CFM_TO_HOST_SET(control->ctrl_flags)) {
host_desc[3] |= CONFIRM_REQUIRED_TO_HOST; //! This bit is used to set CONFIRM_REQUIRED_TO_HOST in firmware.
}
host_desc[4] = ext_desc_size; //! xtend_desc size
host_desc[5] = (uint8_t)((mac_hdr_len + 3) & ~3); //! Mac_header length
if (IS_BCAST_MCAST_MAC(control->addr1[0])) {
host_desc[7] |= BCAST_INDICATION; //! Bcast_indication
//! If auto-rate is enabled for bcast/mcast pkts, use 1 Mbps
if (!IS_FIXED_DATA_RATE(control->ctrl_flags)) {
host_desc[6] |= MAC_INFO_ENABLE; //! Fixed Rate
host_desc[8] = SL_WIFI_DATA_RATE_1;
}
}
if (IS_FIXED_DATA_RATE(control->ctrl_flags)) {
host_desc[6] |= MAC_INFO_ENABLE; //! Fixed Rate
host_desc[8] = (uint8_t)control->rate;
}
if (IS_QOS_PKT(control->ctrl_flags) && !IS_BCAST_MCAST_MAC(control->addr1[0])) {
host_desc[13] |= QOS_ENABLE; // QOS ENABLE
}
host_desc[14] =
(uint8_t)(((WME_AC_TO_TID(control->priority) & 0xf) << 4) | (WME_AC_TO_QNUM(control->priority) & 0xf));
//! Initialize extended desc
memcpy(&host_desc[16], &control->token, TRANSCEIVER_TX_DATA_EXT_DESC_SIZE);
// Send command packet to the SI91x socket data queue and await a response
return sl_si91x_driver_send_data_packet(buffer, wait_time);
}
sl_status_t sl_si91x_bl_upgrade_firmware(uint8_t *firmware_image, uint32_t fw_image_size, uint8_t flags)
{
static uint16_t boot_cmd = 0;
uint16_t read_value = 0;
uint32_t offset = 0;
uint32_t retval = 0;
uint32_t boot_insn = 0;
uint32_t poll_resp = 0;
//! If it is a start of file set the boot cmd to pong valid
if (flags & SL_SI91X_FW_START_OF_FILE) {
boot_cmd = RSI_HOST_INTERACT_REG_VALID | RSI_PONG_VALID;
}
//! check for invalid packet
if ((fw_image_size % SL_SI91X_MIN_CHUNK_SIZE != 0) && (!(flags & SL_SI91X_FW_END_OF_FILE))) {
return SL_STATUS_FAIL;
}
//! loop to execute multiple of 4K chunks
while (offset < fw_image_size) {
switch (boot_cmd) {
case (RSI_HOST_INTERACT_REG_VALID | RSI_PING_VALID):
boot_insn = RSI_PONG_WRITE;
poll_resp = RSI_PING_AVAIL;
boot_cmd = RSI_HOST_INTERACT_REG_VALID | RSI_PONG_VALID;
break;
case (RSI_HOST_INTERACT_REG_VALID | RSI_PONG_VALID):
boot_insn = RSI_PING_WRITE;
poll_resp = RSI_PONG_AVAIL;
boot_cmd = RSI_HOST_INTERACT_REG_VALID | RSI_PING_VALID;
break;
default:
return SL_STATUS_FAIL;
}
retval = sl_si91x_boot_instruction((uint8_t)boot_insn, (uint16_t *)(firmware_image + offset));
VERIFY_STATUS_AND_RETURN(retval);
while (1) {
retval = sl_si91x_boot_instruction(RSI_REG_READ, &read_value);
VERIFY_STATUS_AND_RETURN(retval);
if (read_value == (RSI_HOST_INTERACT_REG_VALID | poll_resp)) {
break;
}
}
offset += SL_SI91X_MIN_CHUNK_SIZE;
}
//! For last chunk set boot cmd as End of file reached
if (flags & SL_SI91X_FW_END_OF_FILE) {
boot_cmd = RSI_HOST_INTERACT_REG_VALID | RSI_EOF_REACHED;
retval = sl_si91x_boot_instruction(RSI_REG_WRITE, &boot_cmd);
VERIFY_STATUS_AND_RETURN(retval);
//! check for successful firmware upgrade
do {
retval = sl_si91x_boot_instruction(RSI_REG_READ, &read_value);
VERIFY_STATUS_AND_RETURN(retval);
} while (read_value != (RSI_HOST_INTERACT_REG_VALID | RSI_FWUP_SUCCESSFUL));
}
return retval;
}
sl_status_t sl_si91x_set_fast_fw_up(void)
{
uint32_t read_data = 0;
sl_status_t retval = 0;
retval = sl_si91x_bus_read_memory(SL_SI91X_SAFE_UPGRADE_ADDR, 4, (uint8_t *)&read_data);
VERIFY_STATUS_AND_RETURN(retval);
//disabling safe upgradation bit
if (read_data & SL_SI91X_SAFE_UPGRADE) {
read_data &= ~(SL_SI91X_SAFE_UPGRADE);
retval = sl_si91x_bus_write_memory(SL_SI91X_SAFE_UPGRADE_ADDR, 4, (uint8_t *)&read_data);
VERIFY_STATUS_AND_RETURN(retval);
}
return retval;
}
void sli_si91x_append_to_buffer_queue(sl_si91x_buffer_queue_t *queue, sl_wifi_buffer_t *buffer)
{
CORE_irqState_t state = CORE_EnterAtomic();
if (queue->tail == NULL) {
assert(queue->head == NULL); // Both should be NULL at the same time
queue->head = buffer;
queue->tail = buffer;
} else {
queue->tail->node.node = &buffer->node;
queue->tail = buffer;
}
CORE_ExitAtomic(state);
}
sl_status_t sli_si91x_pop_from_buffer_queue(sl_si91x_buffer_queue_t *queue, sl_wifi_buffer_t **buffer)
{
sl_status_t status = SL_STATUS_EMPTY;
CORE_irqState_t state = CORE_EnterAtomic();
if (queue->head == NULL) {
assert(queue->tail == NULL); // Both should be NULL at the same time
*buffer = NULL;
status = SL_STATUS_EMPTY;
} else {
*buffer = queue->head;
status = SL_STATUS_OK;
if (queue->head == queue->tail) {
queue->head = NULL;
queue->tail = NULL;
} else {
queue->head = (sl_wifi_buffer_t *)queue->head->node.node;
}
}
CORE_ExitAtomic(state);
return status;
}
sl_status_t sl_si91x_get_firmware_version(sl_si91x_firmware_version_t *version)
{
sl_status_t status = SL_STATUS_OK;
sl_wifi_buffer_t *buffer = NULL;
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
SL_WIFI_ARGS_CHECK_NULL_POINTER(version);
status = sl_si91x_driver_send_command(RSI_WLAN_REQ_FULL_FW_VERSION,
SI91X_WLAN_CMD,
NULL,
0,
SL_SI91X_WAIT_FOR_RESPONSE(1000),
NULL,
&buffer);
if ((status != SL_STATUS_OK) && (buffer != NULL)) {
sl_si91x_host_free_buffer(buffer);
}
VERIFY_STATUS_AND_RETURN(status);
sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
if (packet == NULL) {
return SL_STATUS_NULL_POINTER;
}
if (packet->length > 0) {
const sl_wifi_firmware_version_t *response = (const sl_wifi_firmware_version_t *)packet->data;
if (response == NULL) {
return SL_STATUS_NULL_POINTER;
}
version->chip_id = response->chip_id;
version->rom_id = response->rom_id;
version->major = response->major;
version->minor = response->minor;
version->security_version = response->security_version;
version->patch_num = response->patch_num;
version->customer_id = response->customer_id;
version->build_num = (packet->data[7] | packet->data[8]);
}
sl_si91x_host_free_buffer(buffer);
return status;
}
sl_status_t sl_si91x_get_firmware_size(void *buffer, uint32_t *fw_image_size)
{
SL_WIFI_ARGS_CHECK_NULL_POINTER(buffer);
const sl_si91x_firmware_header_t *fw = (const sl_si91x_firmware_header_t *)buffer;
*fw_image_size = (fw->image_size + sizeof(sl_si91x_firmware_header_t));
return SL_STATUS_OK;
}
sl_status_t sl_si91x_set_nwp_config_request(sl_si91x_nwp_configuration_t nwp_config)
{
sl_status_t status = SL_STATUS_OK;
if ((nwp_config.code & SL_SI91X_XO_CTUNE_FROM_HOST) || (nwp_config.code & SL_SI91X_ENABLE_NWP_WDT_FROM_HOST)
|| (nwp_config.code & SL_SI91X_DISABLE_NWP_WDT_FROM_HOST)) {
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_SET_CONFIG,
SI91X_COMMON_CMD,
&nwp_config,
sizeof(sl_si91x_nwp_configuration_t),
SL_SI91X_WAIT_FOR_RESPONSE(3000),
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
} else
return SL_STATUS_NOT_SUPPORTED;
return status;
}
sl_status_t sl_si91x_get_nwp_config(const sl_si91x_nwp_get_configuration_t *nwp_config, uint8_t *response)
{
sl_status_t status = SL_STATUS_OK;
sl_wifi_buffer_t *buffer = NULL;
sl_si91x_packet_t *packet = NULL;
if (nwp_config->sub_command_type == GET_OPN_BOARD_CONFIG) {
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_GET_CONFIG,
SI91X_COMMON_CMD,
nwp_config,
sizeof(sl_si91x_nwp_get_configuration_t),
SL_SI91X_WAIT_FOR_RESPONSE(3000),
NULL,
&buffer);
if (status != SL_STATUS_OK) {
if (buffer != NULL)
sl_si91x_host_free_buffer(buffer);
}
VERIFY_STATUS_AND_RETURN(status);
packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
memcpy(response, packet->data, packet->length);
sl_si91x_host_free_buffer(buffer);
} else {
return SL_STATUS_NOT_SUPPORTED;
}
return status;
}
sl_status_t sl_si91x_debug_log(sl_si91x_assertion_t *assertion)
{
sl_status_t status = SL_STATUS_OK;
sl_si91x_debug_log_t debug_config = { 0 };
if (!device_initialized) {
return SL_STATUS_NOT_INITIALIZED;
}
if ((debug_config.assertion_type > SL_SI91X_ASSERTION_TYPE_ALL)
|| (debug_config.assertion_level > SL_SI91X_ASSERTION_LEVEL_MAX)) {
return SL_STATUS_INVALID_PARAMETER;
}
debug_config.assertion_type = assertion->assert_type;
debug_config.assertion_level = assertion->assert_level;
status = sl_si91x_driver_send_command(RSI_COMMON_REQ_DEBUG_LOG,
SI91X_COMMON_CMD,
&debug_config,
sizeof(sl_si91x_debug_log_t),
SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
NULL,
NULL);
VERIFY_STATUS_AND_RETURN(status);
return status;
}