blob: 12973d3c8ffb6721ce398dcba527160f8b4400f4 [file] [log] [blame]
/*
*
* Copyright (c) 2022 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.
*/
/* Includes */
#include "em_gpio.h"
#include "sl_wfx.h"
#include "sl_wfx_board.h"
// File specific to each platform, it must be created for custom boards
#include "sl_wfx_pds.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Firmware include */
#include "sl_wfx_wf200_C0.h"
#include "FreeRTOS.h"
#include "event_groups.h"
#include "task.h"
#include "AppConfig.h"
#include "sl_wfx_host.h"
#include "sl_wfx_task.h"
#include "wfx_host_events.h"
#include "sl_spidrv_instances.h"
#include "spidrv.h"
#define SL_WFX_EVENT_MAX_SIZE 512
#define SL_WFX_EVENT_LIST_SIZE 1
StaticSemaphore_t xWfxWakeupSemaBuffer;
uint8_t sWfxEventQueueBuffer[SL_WFX_EVENT_LIST_SIZE * sizeof(uint8_t)];
StaticQueue_t sWfxEventQueueStruct;
QueueHandle_t wfx_event_Q = NULL;
SemaphoreHandle_t wfx_wakeup_sem = NULL;
SemaphoreHandle_t wfx_mutex = NULL;
StaticSemaphore_t xWfxMutexBuffer;
struct
{
uint32_t wf200_firmware_download_progress;
int wf200_initialized;
uint8_t waited_event_id;
uint8_t posted_event_id;
} host_context;
#ifdef SL_WFX_USE_SDIO
#ifdef SLEEP_ENABLED
sl_status_t sl_wfx_host_enable_sdio(void);
sl_status_t sl_wfx_host_disable_sdio(void);
#endif
#endif
#ifdef SL_WFX_USE_SPI
#ifdef SLEEP_ENABLED
sl_status_t sl_wfx_host_enable_spi(void);
sl_status_t sl_wfx_host_disable_spi(void);
#endif
#endif
/****************************************************************************
* @fn sl_status_t wfx_soft_init(void)
* @brief
* WFX FMAC driver host interface initialization
* @param[in] None
* @returns Returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t wfx_soft_init(void)
{
SILABS_LOG("WF200:Soft Init");
if ((wfx_event_Q = xQueueCreateStatic(SL_WFX_EVENT_LIST_SIZE, sizeof(uint8_t), sWfxEventQueueBuffer, &sWfxEventQueueStruct)) ==
NULL)
{
return SL_STATUS_FAIL;
}
if ((wfx_wakeup_sem = xSemaphoreCreateBinaryStatic(&xWfxWakeupSemaBuffer)) == NULL)
{
return SL_STATUS_FAIL;
}
if ((wfx_mutex = xSemaphoreCreateMutexStatic(&xWfxMutexBuffer)) == NULL)
{
return SL_STATUS_FAIL;
}
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_init(void)
* @brief
* Notify driver init function
* @param[in] None
* @returns Returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_init(void)
{
SILABS_LOG("WFX: Host Init");
host_context.wf200_firmware_download_progress = 0;
host_context.wf200_initialized = 0;
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_get_firmware_data(const uint8_t **data, uint32_t data_size)
* @brief
* Get firmware data
* @param[in] data:
* @param[in] data_size:
* @returns Returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_get_firmware_data(const uint8_t ** data, uint32_t data_size)
{
*data = &sl_wfx_firmware[host_context.wf200_firmware_download_progress];
host_context.wf200_firmware_download_progress += data_size;
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_get_firmware_size(uint32_t *firmware_size)
* @brief
* Get firmware size
* @param[in] firmware_size:
* @returns Returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_get_firmware_size(uint32_t * firmware_size)
{
*firmware_size = sizeof(sl_wfx_firmware);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_get_pds_data(const char **pds_data, uint16_t index)
* @brief
* Get PDS data
* @param[in] pds_data:
* @param[in] index:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_get_pds_data(const char ** pds_data, uint16_t index)
{
*pds_data = sl_wfx_pds[index];
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_get_pds_size(uint16_t *pds_size)
* @brief
* Get PDS size
* @param[in] pds_size:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_get_pds_size(uint16_t * pds_size)
{
*pds_size = SL_WFX_ARRAY_COUNT(sl_wfx_pds);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_deinit(void)
* @brief
* Deinit host interface
* @param[in] None
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_deinit(void)
{
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_allocate_buffer(void **buffer, sl_wfx_buffer_type_t type, uint32_t buffer_size)
* @brief
* Allocate buffer (Should allocate either Ethernet - from LWIP or Control) - TODO
* @param[in] buffer:
* @param[in] type:
* @param[in] buffer_size:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_allocate_buffer(void ** buffer, sl_wfx_buffer_type_t type, uint32_t buffer_size)
{
if ((*buffer = pvPortMalloc(buffer_size)) == (void *) 0)
{
return SL_STATUS_FAIL;
}
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_free_buffer(void *buffer, sl_wfx_buffer_type_t type)
* @brief
* Free host buffer (CHECK LWIP buffer)
* @param[in] buffer:
* @param[in] type:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_free_buffer(void * buffer, sl_wfx_buffer_type_t type)
{
vPortFree(buffer);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_hold_in_reset(void)
* @brief
* Set reset pin low
* @param[in] None
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_hold_in_reset(void)
{
GPIO_PinOutClear(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN);
host_context.wf200_initialized = 0;
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_set_wake_up_pin(uint8_t state)
* @brief
* Set wakeup pin status
* @param[in] state:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_set_wake_up_pin(uint8_t state)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
if (state > PINOUT_CLEAR_STATUS)
{
#ifdef SLEEP_ENABLED
#ifdef SL_WFX_USE_SDIO
sl_wfx_host_enable_sdio();
#endif
#ifdef SL_WFX_USE_SPI
sl_wfx_host_enable_spi();
#endif
#endif
GPIO_PinOutSet(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN);
}
else
{
GPIO_PinOutClear(SL_WFX_HOST_PINOUT_WUP_PORT, SL_WFX_HOST_PINOUT_WUP_PIN);
#ifdef SLEEP_ENABLED
#ifdef SL_WFX_USE_SDIO
sl_wfx_host_disable_sdio();
#endif
#ifdef SL_WFX_USE_SPI
sl_wfx_host_disable_spi();
#endif
#endif
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_reset_chip(void)
* @brief
* reset the host chip
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_reset_chip(void)
{
// Pull it low for at least 1 ms to issue a reset sequence
GPIO_PinOutClear(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN);
// Delay for 10ms
vTaskDelay(pdMS_TO_TICKS(10));
// Hold pin high to get chip out of reset
GPIO_PinOutSet(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN);
// Delay for 3ms
vTaskDelay(pdMS_TO_TICKS(3));
host_context.wf200_initialized = 0;
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_wait_for_wake_up(void)
* @brief
* wait for the host wake up
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_wait_for_wake_up(void)
{
xSemaphoreTake(wfx_wakeup_sem, TICKS_TO_WAIT_0);
xSemaphoreTake(wfx_wakeup_sem, TICKS_TO_WAIT_3 / portTICK_PERIOD_MS);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_wait(uint32_t wait_time)
* @brief
* wait for the host
* @param[in] wait_time:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_wait(uint32_t wait_time)
{
uint32_t ticks = pdMS_TO_TICKS(wait_time);
vTaskDelay(ticks ? ticks : 10);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_setup_waited_event(uint8_t event_id)
* @brief
* Called when the driver needs to setup the waited event
* @param[in] event_id:
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_setup_waited_event(uint8_t event_id)
{
host_context.waited_event_id = event_id;
host_context.posted_event_id = 0;
return SL_STATUS_OK;
}
/****************************************************************************
* @fn uint8_t sl_wfx_host_get_waited_event(void)
* @brief
* Called when the driver get waited event
* @returns returns host_context.waited_event_id
*****************************************************************************/
uint8_t sl_wfx_host_get_waited_event(void)
{
return host_context.waited_event_id;
}
/******************************************************************************
* @fn sl_status_t sl_wfx_host_wait_for_confirmation(uint8_t confirmation_id, uint32_t timeout, void **event_payload_out)
* @brief
* wait for the host confirmation
* @param[in] confirmation_id:
* @param[in] timeout:
* @param[in] event_payload_out:
* @returns Returns SL_STATUS_OK if successful,
* Timeout, SL_STATUS_TIMEOUT otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_wait_for_confirmation(uint8_t confirmation_id, uint32_t timeout, void ** event_payload_out)
{
uint8_t posted_event_id;
for (uint32_t i = 0; i < timeout; i++)
{
/* Wait for an event posted by the function sl_wfx_host_post_event() */
if (xQueueReceive(wfx_event_Q, &posted_event_id, TICKS_TO_WAIT_1) == pdTRUE)
{
/* Once a message is received, check if it is the expected ID */
if (confirmation_id == posted_event_id)
{
/* Pass the confirmation reply and return*/
if (event_payload_out != NULL)
{
*event_payload_out = sl_wfx_context->event_payload_buffer;
}
return SL_STATUS_OK;
}
}
}
/* The wait for the confirmation timed out, return */
return SL_STATUS_TIMEOUT;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_lock(void)
* @brief
* Called when the driver needs to lock its access
* @returns Returns SL_STATUS_OK if successful,
*SL_STATUS_TIMEOUT otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_lock(void)
{
sl_status_t status = SL_STATUS_OK;
if (xSemaphoreTake(wfx_mutex, TICKS_TO_WAIT_500) != pdTRUE)
{
SILABS_LOG("*ERR*Wi-Fi driver mutex timo");
status = SL_STATUS_TIMEOUT;
}
return status;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_unlock(void)
* @brief
* Called when the driver needs to unlock its access
* @returns Returns SL_STATUS_OK
*****************************************************************************/
sl_status_t sl_wfx_host_unlock(void)
{
xSemaphoreGive(wfx_mutex);
return SL_STATUS_OK;
}
/******************************************************************************
* @fn sl_status_t sl_wfx_host_post_event(sl_wfx_generic_message_t *event_payload)
* @brief
* Called when the driver needs to post an event
* @param[in] event_payload:
* @returns Returns status
*****************************************************************************/
sl_status_t sl_wfx_host_post_event(sl_wfx_generic_message_t * event_payload)
{
sl_status_t status;
/* Forward the message to the application */
status = sl_wfx_host_process_event(event_payload);
if (host_context.waited_event_id == event_payload->header.id)
{
if (event_payload->header.length < SL_WFX_EVENT_MAX_SIZE)
{
/* Post the event in the queue */
memcpy(sl_wfx_context->event_payload_buffer, (void *) event_payload, event_payload->header.length);
host_context.posted_event_id = event_payload->header.id;
xQueueOverwrite(wfx_event_Q, (void *) &event_payload->header.id);
}
}
return status;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_transmit_frame(void *frame, uint32_t frame_len)
* @brief
* Called when the driver needs to transmit a frame
* @param[in] frame:
* @param[in] frame_len:
* @returns returns sl_wfx_data_write(frame, frame_len)
*****************************************************************************/
sl_status_t sl_wfx_host_transmit_frame(void * frame, uint32_t frame_len)
{
return sl_wfx_data_write(frame, frame_len);
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_sleep_grant(sl_wfx_host_bus_transfer_type_t type,
sl_wfx_register_address_t address,
uint32_t length)
* @brief
* Called when the driver is considering putting the
* WFx in sleep mode
* @param[in] type:
* @param[in] address:
* @param[in] length:
* @returns SL_WIFI_SLEEP_GRANTED to let the WFx go to
*sleep, SL_WIFI_SLEEP_NOT_GRANTED otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_sleep_grant(sl_wfx_host_bus_transfer_type_t type, sl_wfx_register_address_t address, uint32_t length)
{
(void) (type);
(void) (address);
(void) (length);
return SL_STATUS_WIFI_SLEEP_GRANTED;
}
#if SL_WFX_DEBUG_MASK
/****************************************************************************
* @fn void sl_wfx_host_log(const char *str, ...)
* @brief
* Host debug output
* @param[in] str: string
* @return None
*****************************************************************************/
void sl_wfx_host_log(const char * str, ...)
{
va_list args;
va_start(args, str);
vprintf(str, args);
va_end(args);
}
#endif
#ifndef PW_RPC_ENABLED
/* Place holder - This is just to handle UART interrupts
* The "otThread tasks handles it. WiFi does not need it yet
* I don't care for it. I should really have the thread
* shut it off
*/
#if !CHIP_ENABLE_OPENTHREAD
/****************************************************************************
* @fn void otSysEventSignalPending(void)
* @brief
* system event signal pending
* @param[in] None
* @return None
*****************************************************************************/
void otSysEventSignalPending(void)
{
// BaseType_t yieldRequired = ThreadStackMgrImpl().SignalThreadActivityPendingFromISR();
SILABS_LOG("*ERR*UART intr - NOT Handled");
portYIELD_FROM_ISR(pdFALSE);
}
#endif /* !CHIP_ENABLE_OPENTHREAD */
#endif /* PW_RPC_ENABLED */