P4 fixes
This commit is contained in:
18
resources/espressif__esp_hosted/host/drivers/bt/hci_drv.h
Normal file
18
resources/espressif__esp_hosted/host/drivers/bt/hci_drv.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#ifndef __HOSTED_HCI_DRV_H
|
||||
#define __HOSTED_HCI_DRV_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "esp_hosted_bt_config.h"
|
||||
|
||||
void hci_drv_init(void);
|
||||
|
||||
void hci_drv_show_configuration(void);
|
||||
|
||||
// Handles BT Rx
|
||||
int hci_rx_handler(interface_buffer_handle_t *buf_handle);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#include "hci_drv.h"
|
||||
|
||||
#include "esp_hosted_log.h"
|
||||
static const char TAG[] = "hci_stub_drv";
|
||||
|
||||
#if H_BT_HOST_ESP_NIMBLE
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
#include "nimble/transport.h"
|
||||
#endif
|
||||
|
||||
#if H_BT_HOST_ESP_BLUEDROID
|
||||
#include "esp_hosted_bt.h"
|
||||
#endif
|
||||
|
||||
#define WEAK __attribute__((weak))
|
||||
|
||||
int hci_rx_handler(interface_buffer_handle_t *buf_handle)
|
||||
{
|
||||
/* Hosted transport received BT packets, but Hosted was not
|
||||
* configured to handle BT packets. Drop them.
|
||||
*/
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void hci_drv_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void hci_drv_show_configuration(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Host BT Support: Disabled");
|
||||
}
|
||||
|
||||
#if H_BT_HOST_ESP_NIMBLE
|
||||
/**
|
||||
* ESP NimBLE expects these interfaces for Tx
|
||||
*
|
||||
* There are marked as weak references:
|
||||
*
|
||||
* - to allow ESP NimBLE BT Host code to override the functions if
|
||||
* NimBLE BT Host is configured to act as the HCI transport
|
||||
*
|
||||
* - to allow the User to use their own ESP NimBLE HCI transport code
|
||||
* without causing linker errors from Hosted
|
||||
*
|
||||
* - to allow Hosted code to build without linker errors if ESP NimBLE
|
||||
* BT Host is enabled, but Hosted is not configured as HCI transport
|
||||
* and there is no other ESP NimBLE HCI transport code being
|
||||
* used. In this case, the stub functions are used and drops the
|
||||
* incoming data.
|
||||
*/
|
||||
|
||||
WEAK int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
|
||||
{
|
||||
os_mbuf_free_chain(om);
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
WEAK int ble_transport_to_ll_cmd_impl(void *buf)
|
||||
{
|
||||
ble_transport_free(buf);
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif // H_BT_HOST_ESP_NIMBLE
|
||||
|
||||
#if H_BT_HOST_ESP_BLUEDROID
|
||||
WEAK void hosted_hci_bluedroid_open(void)
|
||||
{
|
||||
}
|
||||
|
||||
WEAK void hosted_hci_bluedroid_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
WEAK void hosted_hci_bluedroid_send(uint8_t *data, uint16_t len)
|
||||
{
|
||||
}
|
||||
|
||||
WEAK bool hosted_hci_bluedroid_check_send_available(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WEAK esp_err_t hosted_hci_bluedroid_register_host_callback(const esp_bluedroid_hci_driver_callbacks_t *callback)
|
||||
{
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif // H_BT_HOST_ESP_BLUEDROID
|
||||
263
resources/espressif__esp_hosted/host/drivers/bt/vhci_drv.c
Normal file
263
resources/espressif__esp_hosted/host/drivers/bt/vhci_drv.c
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "os_wrapper.h"
|
||||
#include "transport_drv.h"
|
||||
|
||||
#include "hci_drv.h"
|
||||
|
||||
#if H_BT_HOST_ESP_NIMBLE
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
#include "os/os_mbuf.h"
|
||||
#include "nimble/transport.h"
|
||||
#include "nimble/transport/hci_h4.h"
|
||||
#include "nimble/hci_common.h"
|
||||
#endif
|
||||
|
||||
#if H_BT_HOST_ESP_BLUEDROID
|
||||
#include "esp_hosted_bt.h"
|
||||
#endif
|
||||
|
||||
#include "esp_hosted_log.h"
|
||||
static const char TAG[] = "vhci_drv";
|
||||
|
||||
#if H_BT_HOST_ESP_NIMBLE
|
||||
#define BLE_HCI_EVENT_HDR_LEN (2)
|
||||
#define BLE_HCI_CMD_HDR_LEN (3)
|
||||
#endif
|
||||
|
||||
void hci_drv_init(void)
|
||||
{
|
||||
// do nothing for VHCI: underlying transport should be ready
|
||||
}
|
||||
|
||||
void hci_drv_show_configuration(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Host BT Support: Enabled");
|
||||
ESP_LOGI(TAG, "\tBT Transport Type: VHCI");
|
||||
}
|
||||
|
||||
#if H_BT_HOST_ESP_NIMBLE
|
||||
/**
|
||||
* HCI_H4_xxx is the first byte of the received data
|
||||
*/
|
||||
int hci_rx_handler(interface_buffer_handle_t *buf_handle)
|
||||
{
|
||||
uint8_t * data = buf_handle->payload;
|
||||
uint32_t len_total_read = buf_handle->payload_len;
|
||||
|
||||
int rc;
|
||||
|
||||
if (data[0] == HCI_H4_EVT) {
|
||||
uint8_t *evbuf;
|
||||
int totlen;
|
||||
|
||||
totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
|
||||
if (totlen > UINT8_MAX + BLE_HCI_EVENT_HDR_LEN) {
|
||||
ESP_LOGE(TAG, "Rx: len[%d] > max INT [%d], drop",
|
||||
totlen, UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (totlen > MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) {
|
||||
ESP_LOGE(TAG, "Rx: len[%d] > max BLE [%d], drop",
|
||||
totlen, MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
|
||||
ESP_LOGE(TAG, "Rx: HW_ERROR");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Allocate LE Advertising Report Event from lo pool only */
|
||||
if ((data[1] == BLE_HCI_EVCODE_LE_META) &&
|
||||
(data[3] == BLE_HCI_LE_SUBEV_ADV_RPT || data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
|
||||
evbuf = ble_transport_alloc_evt(1);
|
||||
/* Skip advertising report if we're out of memory */
|
||||
if (!evbuf) {
|
||||
ESP_LOGW(TAG, "Rx: Drop ADV Report Event: NimBLE OOM (not fatal)");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
evbuf = ble_transport_alloc_evt(0);
|
||||
if (!evbuf) {
|
||||
ESP_LOGE(TAG, "Rx: failed transport_alloc_evt(0)");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(evbuf, 0, sizeof * evbuf);
|
||||
memcpy(evbuf, &data[1], totlen);
|
||||
|
||||
rc = ble_transport_to_hs_evt(evbuf);
|
||||
if (rc) {
|
||||
ESP_LOGE(TAG, "Rx: transport_to_hs_evt failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else if (data[0] == HCI_H4_ACL) {
|
||||
struct os_mbuf *m = NULL;
|
||||
|
||||
m = ble_transport_alloc_acl_from_ll();
|
||||
if (!m) {
|
||||
ESP_LOGE(TAG, "Rx: alloc_acl_from_ll failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) {
|
||||
ESP_LOGE(TAG, "Rx: failed os_mbuf_append; rc = %d", rc);
|
||||
os_mbuf_free_chain(m);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ble_transport_to_hs_acl(m);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* ESP NimBLE expects these interfaces for Tx
|
||||
*
|
||||
* For doing non-zero copy:
|
||||
* - transport expects the HCI_H4_xxx type to be the first byte of the
|
||||
* data stream
|
||||
*
|
||||
* For doing zero copy:
|
||||
* - fill in esp_paylod_header and payload data
|
||||
* - HCI_H4_xxx type should be set in esp_payload_header.hci_pkt_type
|
||||
*/
|
||||
|
||||
#if H_BT_ENABLE_LL_INIT
|
||||
void ble_transport_ll_init(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(transport_drv_reconfigure());
|
||||
}
|
||||
|
||||
void ble_transport_ll_deinit(void)
|
||||
{
|
||||
// transport may still be in used for other data (serial, Wi-Fi, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
|
||||
{
|
||||
// TODO: zerocopy version
|
||||
|
||||
// calculate data length from the incoming data
|
||||
int data_len = OS_MBUF_PKTLEN(om) + 1;
|
||||
|
||||
uint8_t * data = NULL;
|
||||
int res;
|
||||
|
||||
data = MEM_ALLOC(data_len);
|
||||
if (!data) {
|
||||
ESP_LOGE(TAG, "Tx %s: malloc failed", __func__);
|
||||
res = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data[0] = HCI_H4_ACL;
|
||||
res = ble_hs_mbuf_to_flat(om, &data[1], OS_MBUF_PKTLEN(om), NULL);
|
||||
if (res) {
|
||||
ESP_LOGE(TAG, "Tx: Error copying HCI_H4_ACL data %d", res);
|
||||
res = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
res = esp_hosted_tx(ESP_HCI_IF, 0, data, data_len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
|
||||
|
||||
exit:
|
||||
os_mbuf_free_chain(om);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ble_transport_to_ll_cmd_impl(void *buf)
|
||||
{
|
||||
// TODO: zerocopy version
|
||||
|
||||
// calculate data length from the incoming data
|
||||
int buf_len = 3 + ((uint8_t *)buf)[2] + 1;
|
||||
|
||||
uint8_t * data = NULL;
|
||||
int res;
|
||||
|
||||
data = MEM_ALLOC(buf_len);
|
||||
if (!data) {
|
||||
ESP_LOGE(TAG, "Tx %s: malloc failed", __func__);
|
||||
res = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data[0] = HCI_H4_CMD;
|
||||
memcpy(&data[1], buf, buf_len - 1);
|
||||
|
||||
res = esp_hosted_tx(ESP_HCI_IF, 0, data, buf_len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
|
||||
|
||||
exit:
|
||||
ble_transport_free(buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif // H_BT_HOST_ESP_NIMBLE
|
||||
|
||||
#if H_BT_HOST_ESP_BLUEDROID
|
||||
static esp_bluedroid_hci_driver_callbacks_t s_callback = { 0 };
|
||||
|
||||
int hci_rx_handler(interface_buffer_handle_t *buf_handle)
|
||||
{
|
||||
uint8_t * data = buf_handle->payload;
|
||||
uint32_t len_total_read = buf_handle->payload_len;
|
||||
|
||||
if (s_callback.notify_host_recv) {
|
||||
s_callback.notify_host_recv(data, len_total_read);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void hosted_hci_bluedroid_open(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(transport_drv_reconfigure());
|
||||
}
|
||||
|
||||
void hosted_hci_bluedroid_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t hosted_hci_bluedroid_register_host_callback(const esp_bluedroid_hci_driver_callbacks_t *callback)
|
||||
{
|
||||
s_callback.notify_host_send_available = callback->notify_host_send_available;
|
||||
s_callback.notify_host_recv = callback->notify_host_recv;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void hosted_hci_bluedroid_send(uint8_t *data, uint16_t len)
|
||||
{
|
||||
int res;
|
||||
uint8_t * ptr = NULL;
|
||||
|
||||
ptr = MEM_ALLOC(len);
|
||||
if (!ptr) {
|
||||
ESP_LOGE(TAG, "%s: malloc failed", __func__);
|
||||
return;
|
||||
}
|
||||
memcpy(ptr, data, len);
|
||||
|
||||
res = esp_hosted_tx(ESP_HCI_IF, 0, ptr, len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
|
||||
|
||||
if (res) {
|
||||
ESP_LOGE(TAG, "%s: Tx failed", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
bool hosted_hci_bluedroid_check_send_available(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // H_BT_HOST_ESP_BLUEDROID
|
||||
@@ -0,0 +1,7 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
set(srcs "mempool.c" )
|
||||
set(priv_requires "")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
157
resources/espressif__esp_hosted/host/drivers/mempool/mempool.c
Normal file
157
resources/espressif__esp_hosted/host/drivers/mempool/mempool.c
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "mempool.h"
|
||||
#include "esp_hosted_config.h"
|
||||
#include "stats.h"
|
||||
#include "esp_log.h"
|
||||
#define MEMPOOL_DEBUG 1
|
||||
|
||||
|
||||
static char * MEM_TAG = "mpool";
|
||||
#if H_MEM_STATS
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
struct mempool * mempool_create(uint32_t block_size)
|
||||
{
|
||||
#ifdef H_USE_MEMPOOL
|
||||
struct mempool * new = (struct mempool *)g_h.funcs->_h_malloc(MEMPOOL_ALIGNED(sizeof(struct mempool)));
|
||||
|
||||
if (!new) {
|
||||
ESP_LOGE(MEM_TAG, "Prob to create mempool size(%u)", MEMPOOL_ALIGNED(sizeof(struct mempool)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!IS_MEMPOOL_ALIGNED((long)new)) {
|
||||
|
||||
ESP_LOGV(MEM_TAG, "Nonaligned");
|
||||
g_h.funcs->_h_free(new);
|
||||
new = (struct mempool *)g_h.funcs->_h_malloc(MEMPOOL_ALIGNED(sizeof(struct mempool)));
|
||||
}
|
||||
|
||||
if (!new) {
|
||||
ESP_LOGE(MEM_TAG, "failed to create mempool size(%u)", MEMPOOL_ALIGNED(sizeof(struct mempool)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new->spinlock = g_h.funcs->_h_create_lock_mempool();
|
||||
|
||||
new->block_size = MEMPOOL_ALIGNED(block_size);
|
||||
SLIST_INIT(&(new->head));
|
||||
|
||||
|
||||
ESP_LOGV(MEM_TAG, "Create mempool %p with block_size:%lu", new, (unsigned long int)block_size);
|
||||
return new;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mempool_destroy(struct mempool* mp)
|
||||
{
|
||||
#ifdef H_USE_MEMPOOL
|
||||
void * node1 = NULL;
|
||||
|
||||
if (!mp)
|
||||
return;
|
||||
|
||||
|
||||
ESP_LOGV(MEM_TAG, "Destroy mempool %p", mp);
|
||||
|
||||
while ((node1 = SLIST_FIRST(&(mp->head))) != NULL) {
|
||||
SLIST_REMOVE_HEAD(&(mp->head), entries);
|
||||
g_h.funcs->_h_free(node1);
|
||||
}
|
||||
SLIST_INIT(&(mp->head));
|
||||
|
||||
g_h.funcs->_h_free(mp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void * mempool_alloc(struct mempool* mp, int nbytes, int need_memset)
|
||||
{
|
||||
void *buf = NULL;
|
||||
|
||||
#ifdef H_USE_MEMPOOL
|
||||
if (!mp || mp->block_size < nbytes)
|
||||
return NULL;
|
||||
|
||||
|
||||
g_h.funcs->_h_lock_mempool(mp->spinlock);
|
||||
|
||||
|
||||
if (!SLIST_EMPTY(&(mp->head))) {
|
||||
buf = SLIST_FIRST(&(mp->head));
|
||||
SLIST_REMOVE_HEAD(&(mp->head), entries);
|
||||
|
||||
|
||||
g_h.funcs->_h_unlock_mempool(mp->spinlock);
|
||||
|
||||
|
||||
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.mp_stats.num_reuse++;
|
||||
ESP_LOGV(MEM_TAG, "%p: num_reuse: %lu", mp, (unsigned long int)(h_stats_g.mp_stats.num_reuse));
|
||||
#endif
|
||||
} else {
|
||||
|
||||
g_h.funcs->_h_unlock_mempool(mp->spinlock);
|
||||
|
||||
buf = MEM_ALLOC(MEMPOOL_ALIGNED(mp->block_size));
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.mp_stats.num_fresh_alloc++;
|
||||
ESP_LOGV(MEM_TAG, "%p: num_alloc: %lu", mp, (unsigned long int)(h_stats_g.mp_stats.num_fresh_alloc));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
buf = g_h.funcs->_h_malloc_align(MEMPOOL_ALIGNED(nbytes), MEMPOOL_ALIGNMENT_BYTES);
|
||||
#endif
|
||||
ESP_LOGV(MEM_TAG, "alloc %u bytes at %p", nbytes, buf);
|
||||
|
||||
if (buf && need_memset)
|
||||
g_h.funcs->_h_memset(buf, 0, nbytes);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
void mempool_free(struct mempool* mp, void *mem)
|
||||
{
|
||||
if (!mem)
|
||||
return;
|
||||
#ifdef H_USE_MEMPOOL
|
||||
if (!mp)
|
||||
return;
|
||||
|
||||
g_h.funcs->_h_lock_mempool(mp->spinlock);
|
||||
|
||||
|
||||
SLIST_INSERT_HEAD(&(mp->head), (struct mempool_entry *)mem, entries);
|
||||
|
||||
g_h.funcs->_h_unlock_mempool(mp->spinlock);
|
||||
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.mp_stats.num_free++;
|
||||
ESP_LOGV(MEM_TAG, "%p: num_ret: %lu", mp, (unsigned long int)(h_stats_g.mp_stats.num_free));
|
||||
#endif
|
||||
|
||||
#else
|
||||
ESP_LOGV(MEM_TAG, "free at %p", mem);
|
||||
g_h.funcs->_h_free_align(mem);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MEMPOOL_H__
|
||||
#define __MEMPOOL_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/queue.h>
|
||||
#include "os_wrapper.h"
|
||||
|
||||
|
||||
#define MEMPOOL_OK 0
|
||||
#define MEMPOOL_FAIL -1
|
||||
|
||||
|
||||
#define LOG printf
|
||||
|
||||
#define MEMPOOL_NAME_STR_SIZE 32
|
||||
|
||||
#define MEMPOOL_ALIGNMENT_BYTES 64
|
||||
#define MEMPOOL_ALIGNMENT_MASK (MEMPOOL_ALIGNMENT_BYTES-1)
|
||||
#define IS_MEMPOOL_ALIGNED(VAL) (!((VAL)& MEMPOOL_ALIGNMENT_MASK))
|
||||
#define MEMPOOL_ALIGNED(VAL) ((VAL) + MEMPOOL_ALIGNMENT_BYTES - \
|
||||
((VAL)& MEMPOOL_ALIGNMENT_MASK))
|
||||
|
||||
#define MEMSET_REQUIRED 1
|
||||
#define MEMSET_NOT_REQUIRED 0
|
||||
|
||||
|
||||
#ifdef H_USE_MEMPOOL
|
||||
struct mempool_entry {
|
||||
SLIST_ENTRY(mempool_entry) entries;
|
||||
};
|
||||
|
||||
typedef SLIST_HEAD(slisthead, mempool_entry) mempool_t;
|
||||
|
||||
struct mempool {
|
||||
mempool_t head;
|
||||
void * spinlock;
|
||||
uint32_t block_size;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mempool * mempool_create(uint32_t block_size);
|
||||
void mempool_destroy(struct mempool* mp);
|
||||
void * mempool_alloc(struct mempool* mp, int nbytes, int need_memset);
|
||||
void mempool_free(struct mempool* mp, void *mem);
|
||||
#endif
|
||||
1050
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_core.c
Normal file
1050
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_core.c
Normal file
File diff suppressed because it is too large
Load Diff
136
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_core.h
Normal file
136
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_core.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Espressif Systems Wireless LAN device driver
|
||||
*
|
||||
* Copyright (C) 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RPC_CORE_H
|
||||
#define __RPC_CORE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "rpc_slave_if.h"
|
||||
#include "os_wrapper.h"
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(n) (1UL << (n))
|
||||
#endif
|
||||
|
||||
#define MAX_SSID_LENGTH 32
|
||||
#define MIN_PWD_LENGTH 8
|
||||
#define MAX_PWD_LENGTH 64
|
||||
#define MIN_CHNL_NO 1
|
||||
#define MAX_CHNL_NO 11
|
||||
#define MIN_CONN_NO 1
|
||||
#define MAX_CONN_NO 10
|
||||
|
||||
#define CLEANUP_APP_MSG(app_msg) do { \
|
||||
if (app_msg) { \
|
||||
if (app_msg->app_free_buff_hdl) { \
|
||||
if (app_msg->app_free_buff_func) { \
|
||||
app_msg->app_free_buff_func(app_msg->app_free_buff_hdl); \
|
||||
app_msg->app_free_buff_hdl = NULL; \
|
||||
} \
|
||||
} \
|
||||
HOSTED_FREE(app_msg); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define RPC_FAIL_ON_NULL_PRINT(msGparaM, prinTmsG) \
|
||||
if (!msGparaM) { \
|
||||
ESP_LOGE(TAG, prinTmsG"\n"); \
|
||||
goto fail_parse_rpc_msg; \
|
||||
}
|
||||
|
||||
#define RPC_FAIL_ON_NULL(msGparaM) \
|
||||
if (!rpc_msg->msGparaM) { \
|
||||
ESP_LOGE(TAG, "Failed to process rx data\n"); \
|
||||
goto fail_parse_rpc_msg; \
|
||||
}
|
||||
|
||||
|
||||
#define RPC_FREE_BUFFS() { \
|
||||
uint8_t idx = 0; \
|
||||
for (idx=0;idx<app_req->n_rpc_free_buff_hdls; idx++) \
|
||||
HOSTED_FREE(app_req->rpc_free_buff_hdls[idx]); \
|
||||
}
|
||||
|
||||
typedef struct q_element {
|
||||
void *buf;
|
||||
int buf_len;
|
||||
} esp_queue_elem_t;
|
||||
|
||||
//g_h.funcs->_h_memcpy(DsT.data, SrC, len_to_cp);
|
||||
|
||||
#if 0
|
||||
#define RPC_REQ_COPY_BYTES(DsT,SrC,SizE) { \
|
||||
if (SizE && SrC) { \
|
||||
DsT.data = (uint8_t *) g_h.funcs->_h_calloc(1, SizE); \
|
||||
if (!DsT.data) { \
|
||||
hosted_log("Failed to allocate memory for req.%s\n",#DsT); \
|
||||
failure_status = RPC_ERR_MEMORY_FAILURE; \
|
||||
goto fail_req; \
|
||||
} \
|
||||
buff_to_free[num_buff_to_free++] = (uint8_t*)DsT.data; \
|
||||
g_h.funcs->_h_memcpy(DsT.data, SrC, SizE); \
|
||||
DsT.len = SizE; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
#define RPC_REQ_COPY_BYTES(DsT,SrC,SizE) { \
|
||||
if (SizE && SrC) { \
|
||||
DsT.data = SrC; \
|
||||
DsT.len = SizE; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RPC_REQ_COPY_STR(DsT,SrC,MaxSizE) { \
|
||||
if (SrC) { \
|
||||
RPC_REQ_COPY_BYTES(DsT, SrC, min(strlen((char*)SrC)+1,MaxSizE)); \
|
||||
} \
|
||||
}
|
||||
|
||||
int rpc_core_init(void);
|
||||
int rpc_core_deinit(void);
|
||||
/*
|
||||
* Allows user app to create low level protobuf request
|
||||
* returns SUCCESS(0) or FAILURE(-1)
|
||||
*/
|
||||
int rpc_send_req(ctrl_cmd_t *app_req);
|
||||
|
||||
/* When request is sent without an async callback, this function will be called
|
||||
* It will wait for control response or timeout for control response
|
||||
* This is only used in synchrounous control path
|
||||
*
|
||||
* Input:
|
||||
* > req - control request from user
|
||||
*
|
||||
* Returns: control response or NULL in case of timeout
|
||||
*
|
||||
**/
|
||||
ctrl_cmd_t * rpc_wait_and_parse_sync_resp(ctrl_cmd_t *req);
|
||||
|
||||
|
||||
/* Checks if async control response callback is available
|
||||
* in argument passed of type control request
|
||||
*
|
||||
* Input:
|
||||
* > req - control request from user
|
||||
*
|
||||
* Returns:
|
||||
* > CALLBACK_AVAILABLE - if a non NULL asynchrounous control response
|
||||
* callback is available
|
||||
* In case of failures -
|
||||
* > MSG_ID_OUT_OF_ORDER - if request msg id is unsupported
|
||||
* > CALLBACK_NOT_REGISTERED - if aync callback is not available
|
||||
**/
|
||||
int compose_rpc_req(Rpc *req, ctrl_cmd_t *app_req, int32_t *failure_status);
|
||||
|
||||
int is_event_callback_registered(int event);
|
||||
|
||||
int rpc_parse_evt(Rpc *rpc_msg, ctrl_cmd_t *app_ntfy);
|
||||
|
||||
int rpc_parse_rsp(Rpc *rpc_msg, ctrl_cmd_t *app_resp);
|
||||
#endif /* __RPC_CORE_H */
|
||||
177
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_evt.c
Normal file
177
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_evt.c
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#include "rpc_core.h"
|
||||
#include "rpc_slave_if.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
|
||||
DEFINE_LOG_TAG(rpc_evt);
|
||||
|
||||
/* For new RPC event (from ESP to host), add up switch case for your message
|
||||
* In general, it is better to subscribe all events or notifications
|
||||
* at slave side & selective subscribe the events at host side.
|
||||
* This way, all the events reach at host and host will decide
|
||||
* if incoming event is expected to be entertained or dropped
|
||||
*
|
||||
* If you are concerned over battery usage, it is code further could be
|
||||
* optimized that only selective events are subscribed at slave and host both sides
|
||||
*
|
||||
* This function will copy rpc event from `Rpc` into
|
||||
* app structure `ctrl_cmd_t`
|
||||
* This function is called after
|
||||
* 1. Protobuf decoding is successful
|
||||
* 2. There is non NULL event callback is available
|
||||
**/
|
||||
int rpc_parse_evt(Rpc *rpc_msg, ctrl_cmd_t *app_ntfy)
|
||||
{
|
||||
if (!rpc_msg || !app_ntfy) {
|
||||
ESP_LOGE(TAG, "NULL rpc event or App struct\n");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
|
||||
app_ntfy->msg_type = RPC_TYPE__Event;
|
||||
app_ntfy->msg_id = rpc_msg->msg_id;
|
||||
app_ntfy->resp_event_status = SUCCESS;
|
||||
|
||||
switch (rpc_msg->msg_id) {
|
||||
|
||||
case RPC_ID__Event_ESPInit: {
|
||||
ESP_LOGI(TAG, "EVENT: ESP INIT\n");
|
||||
break;
|
||||
} case RPC_ID__Event_Heartbeat: {
|
||||
ESP_LOGD(TAG, "EVENT: Heartbeat\n");
|
||||
RPC_FAIL_ON_NULL(event_heartbeat);
|
||||
app_ntfy->u.e_heartbeat.hb_num = rpc_msg->event_heartbeat->hb_num;
|
||||
break;
|
||||
} case RPC_ID__Event_AP_StaConnected: {
|
||||
wifi_event_ap_staconnected_t * p_a = &(app_ntfy->u.e_wifi_ap_staconnected);
|
||||
RpcEventAPStaConnected * p_c = rpc_msg->event_ap_sta_connected;
|
||||
|
||||
RPC_FAIL_ON_NULL(event_ap_sta_connected);
|
||||
app_ntfy->resp_event_status = p_c->resp;
|
||||
|
||||
if(SUCCESS==app_ntfy->resp_event_status) {
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->mac.data, "NULL mac");
|
||||
g_h.funcs->_h_memcpy(p_a->mac, p_c->mac.data, p_c->mac.len);
|
||||
ESP_LOGI(TAG, "EVENT: AP -> sta connected mac[" MACSTR "] (len:%u)",
|
||||
MAC2STR(p_a->mac), p_c->mac.len);
|
||||
}
|
||||
p_a->aid = p_c->aid;
|
||||
p_a->is_mesh_child = p_c->is_mesh_child;
|
||||
|
||||
break;
|
||||
} case RPC_ID__Event_AP_StaDisconnected: {
|
||||
wifi_event_ap_stadisconnected_t * p_a = &(app_ntfy->u.e_wifi_ap_stadisconnected);
|
||||
RpcEventAPStaDisconnected * p_c = rpc_msg->event_ap_sta_disconnected;
|
||||
|
||||
ESP_LOGD(TAG, "EVENT: AP -> sta disconnected");
|
||||
RPC_FAIL_ON_NULL(event_ap_sta_disconnected);
|
||||
app_ntfy->resp_event_status = p_c->resp;
|
||||
|
||||
if(SUCCESS==app_ntfy->resp_event_status) {
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->mac.data, "NULL mac");
|
||||
g_h.funcs->_h_memcpy(p_a->mac, p_c->mac.data, p_c->mac.len);
|
||||
ESP_LOGI(TAG, "EVENT: AP -> sta DISconnected mac[" MACSTR "] (len:%u)",
|
||||
MAC2STR(p_a->mac), p_c->mac.len);
|
||||
}
|
||||
|
||||
p_a->aid = p_c->aid;
|
||||
p_a->is_mesh_child = p_c->is_mesh_child;
|
||||
p_a->reason = p_c->reason;
|
||||
|
||||
break;
|
||||
} case RPC_ID__Event_WifiEventNoArgs: {
|
||||
RPC_FAIL_ON_NULL(event_wifi_event_no_args);
|
||||
app_ntfy->resp_event_status = rpc_msg->event_wifi_event_no_args->resp;
|
||||
ESP_LOGI(TAG, "Event [0x%lx] received", rpc_msg->event_wifi_event_no_args->event_id);
|
||||
app_ntfy->u.e_wifi_simple.wifi_event_id = rpc_msg->event_wifi_event_no_args->event_id;
|
||||
|
||||
switch (rpc_msg->event_wifi_event_no_args->event_id) {
|
||||
/* basic events populated, not all */
|
||||
case WIFI_EVENT_WIFI_READY:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi Ready");
|
||||
break;
|
||||
case WIFI_EVENT_SCAN_DONE:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi scan done");
|
||||
break;
|
||||
case WIFI_EVENT_STA_START:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi Start");
|
||||
break;
|
||||
case WIFI_EVENT_STA_STOP:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi Stop");
|
||||
break;
|
||||
case WIFI_EVENT_STA_CONNECTED:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi Connected");
|
||||
break;
|
||||
case WIFI_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi Disconnected");
|
||||
break;
|
||||
case WIFI_EVENT_STA_AUTHMODE_CHANGE:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi AuthMode change");
|
||||
break;
|
||||
case WIFI_EVENT_AP_START:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi AP Start");
|
||||
break;
|
||||
case WIFI_EVENT_AP_STOP:
|
||||
ESP_LOGI(TAG, "EVT rcvd: Wi-Fi AP stop");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Event_StaScanDone: {
|
||||
RpcEventStaScanDone *p_c = rpc_msg->event_sta_scan_done;
|
||||
wifi_event_sta_scan_done_t *p_a = &app_ntfy->u.e_wifi_sta_scan_done;
|
||||
RPC_FAIL_ON_NULL(event_sta_scan_done);
|
||||
app_ntfy->resp_event_status = p_c->resp;
|
||||
ESP_LOGI(TAG, "Event Scan Done, %ld items", rpc_msg->event_sta_scan_done->scan_done->number);
|
||||
p_a->status = p_c->scan_done->status;
|
||||
p_a->number = p_c->scan_done->number;
|
||||
p_a->scan_id = p_c->scan_done->scan_id;
|
||||
break;
|
||||
} case RPC_ID__Event_StaConnected: {
|
||||
RPC_FAIL_ON_NULL(event_sta_connected);
|
||||
RPC_FAIL_ON_NULL(event_sta_connected->sta_connected);
|
||||
WifiEventStaConnected *p_c = rpc_msg->event_sta_connected->sta_connected;
|
||||
wifi_event_sta_connected_t *p_a = &app_ntfy->u.e_wifi_sta_connected;
|
||||
app_ntfy->resp_event_status = rpc_msg->event_sta_connected->resp;
|
||||
if (SUCCESS == app_ntfy->resp_event_status) {
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->ssid.data, "NULL SSID");
|
||||
g_h.funcs->_h_memcpy(p_a->ssid, p_c->ssid.data, p_c->ssid.len);
|
||||
p_a->ssid_len = p_c->ssid_len;
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->bssid.data, "NULL BSSID");
|
||||
g_h.funcs->_h_memcpy(p_a->bssid, p_c->bssid.data, p_c->bssid.len);
|
||||
p_a->channel = p_c->channel;
|
||||
p_a->authmode = p_c->authmode;
|
||||
p_a->aid = p_c->aid;
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Event_StaDisconnected: {
|
||||
RPC_FAIL_ON_NULL(event_sta_disconnected);
|
||||
RPC_FAIL_ON_NULL(event_sta_disconnected->sta_disconnected);
|
||||
WifiEventStaDisconnected *p_c = rpc_msg->event_sta_disconnected->sta_disconnected;
|
||||
wifi_event_sta_disconnected_t *p_a = &app_ntfy->u.e_wifi_sta_disconnected;
|
||||
app_ntfy->resp_event_status = rpc_msg->event_sta_connected->resp;
|
||||
if (SUCCESS == app_ntfy->resp_event_status) {
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->ssid.data, "NULL SSID");
|
||||
g_h.funcs->_h_memcpy(p_a->ssid, p_c->ssid.data, p_c->ssid.len);
|
||||
p_a->ssid_len = p_c->ssid_len;
|
||||
RPC_FAIL_ON_NULL_PRINT(p_c->bssid.data, "NULL BSSID");
|
||||
g_h.funcs->_h_memcpy(p_a->bssid, p_c->bssid.data, p_c->bssid.len);
|
||||
p_a->reason = p_c->reason;
|
||||
p_a->rssi = p_c->rssi;
|
||||
}
|
||||
break;
|
||||
} default: {
|
||||
ESP_LOGE(TAG, "Invalid/unsupported event[%u] received\n",rpc_msg->msg_id);
|
||||
goto fail_parse_rpc_msg;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
||||
fail_parse_rpc_msg:
|
||||
app_ntfy->resp_event_status = FAILURE;
|
||||
return FAILURE;
|
||||
}
|
||||
510
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_req.c
Normal file
510
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_req.c
Normal file
@@ -0,0 +1,510 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#include "rpc_core.h"
|
||||
#include "rpc_slave_if.h"
|
||||
#include "esp_hosted_rpc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_wifi_config.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_bitmasks.h"
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
DEFINE_LOG_TAG(rpc_req);
|
||||
|
||||
#define ADD_RPC_BUFF_TO_FREE_LATER(BuFf) { \
|
||||
assert((app_req->n_rpc_free_buff_hdls+1)<=MAX_FREE_BUFF_HANDLES); \
|
||||
app_req->rpc_free_buff_hdls[app_req->n_rpc_free_buff_hdls++] = BuFf; \
|
||||
}
|
||||
|
||||
#define RPC_ALLOC_ASSIGN(TyPe,MsG_StRuCt,InItFuNc) \
|
||||
TyPe *req_payload = (TyPe *) \
|
||||
g_h.funcs->_h_calloc(1, sizeof(TyPe)); \
|
||||
if (!req_payload) { \
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for req->%s\n",#MsG_StRuCt); \
|
||||
*failure_status = RPC_ERR_MEMORY_FAILURE; \
|
||||
return FAILURE; \
|
||||
} \
|
||||
req->MsG_StRuCt = req_payload; \
|
||||
InItFuNc(req_payload); \
|
||||
ADD_RPC_BUFF_TO_FREE_LATER((uint8_t*)req_payload);
|
||||
|
||||
//TODO: How this is different in slave_control.c
|
||||
#define RPC_ALLOC_ELEMENT(TyPe,MsG_StRuCt,InIt_FuN) { \
|
||||
TyPe *NeW_AllocN = (TyPe *) g_h.funcs->_h_calloc(1, sizeof(TyPe)); \
|
||||
if (!NeW_AllocN) { \
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for req->%s\n",#MsG_StRuCt); \
|
||||
*failure_status = RPC_ERR_MEMORY_FAILURE; \
|
||||
return FAILURE; \
|
||||
} \
|
||||
ADD_RPC_BUFF_TO_FREE_LATER((uint8_t*)NeW_AllocN); \
|
||||
MsG_StRuCt = NeW_AllocN; \
|
||||
InIt_FuN(MsG_StRuCt); \
|
||||
}
|
||||
|
||||
/* RPC request is simple remote function invokation at slave from host
|
||||
*
|
||||
* For new RPC request, add up switch case for your message
|
||||
* If the RPC function to be invoked does not carry any arguments, just add
|
||||
* case in the top with intentional fall through
|
||||
* If any arguments are needed, you may have to add union for your message
|
||||
* in Ctrl_cmd_t in rpc_api.h and fill the request in new case
|
||||
*
|
||||
* For altogether new RPC function addition, please check
|
||||
* esp_hosted_fg/common/proto/esp_hosted_config.proto
|
||||
*/
|
||||
int compose_rpc_req(Rpc *req, ctrl_cmd_t *app_req, int32_t *failure_status)
|
||||
{
|
||||
switch(req->msg_id) {
|
||||
|
||||
case RPC_ID__Req_GetWifiMode:
|
||||
//case RPC_ID__Req_GetAPConfig:
|
||||
//case RPC_ID__Req_DisconnectAP:
|
||||
//case RPC_ID__Req_GetSoftAPConfig:
|
||||
//case RPC_ID__Req_GetSoftAPConnectedSTAList:
|
||||
//case RPC_ID__Req_StopSoftAP:
|
||||
case RPC_ID__Req_WifiGetPs:
|
||||
case RPC_ID__Req_OTABegin:
|
||||
case RPC_ID__Req_OTAEnd:
|
||||
case RPC_ID__Req_WifiDeinit:
|
||||
case RPC_ID__Req_WifiStart:
|
||||
case RPC_ID__Req_WifiStop:
|
||||
case RPC_ID__Req_WifiConnect:
|
||||
case RPC_ID__Req_WifiDisconnect:
|
||||
case RPC_ID__Req_WifiScanStop:
|
||||
case RPC_ID__Req_WifiScanGetApNum:
|
||||
case RPC_ID__Req_WifiClearApList:
|
||||
case RPC_ID__Req_WifiRestore:
|
||||
case RPC_ID__Req_WifiClearFastConnect:
|
||||
case RPC_ID__Req_WifiStaGetApInfo:
|
||||
case RPC_ID__Req_WifiGetMaxTxPower:
|
||||
case RPC_ID__Req_WifiGetChannel:
|
||||
case RPC_ID__Req_WifiGetCountryCode:
|
||||
case RPC_ID__Req_WifiGetCountry:
|
||||
case RPC_ID__Req_WifiApGetStaList:
|
||||
case RPC_ID__Req_WifiStaGetRssi:
|
||||
case RPC_ID__Req_WifiStaGetNegotiatedPhymode:
|
||||
case RPC_ID__Req_WifiStaGetAid:
|
||||
case RPC_ID__Req_WifiGetBand:
|
||||
case RPC_ID__Req_WifiGetBandMode:
|
||||
case RPC_ID__Req_WifiScanGetApRecord: {
|
||||
/* Intentional fallthrough & empty */
|
||||
break;
|
||||
} case RPC_ID__Req_GetMACAddress: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqGetMacAddress, req_get_mac_address,
|
||||
rpc__req__get_mac_address__init);
|
||||
|
||||
req_payload->mode = app_req->u.wifi_mac.mode;
|
||||
|
||||
break;
|
||||
} case RPC_ID__Req_SetMacAddress: {
|
||||
wifi_mac_t * p = &app_req->u.wifi_mac;
|
||||
RPC_ALLOC_ASSIGN(RpcReqSetMacAddress, req_set_mac_address,
|
||||
rpc__req__set_mac_address__init);
|
||||
|
||||
req_payload->mode = p->mode;
|
||||
RPC_REQ_COPY_BYTES(req_payload->mac, p->mac, BSSID_BYTES_SIZE);
|
||||
|
||||
break;
|
||||
} case RPC_ID__Req_SetWifiMode: {
|
||||
hosted_mode_t * p = &app_req->u.wifi_mode;
|
||||
RPC_ALLOC_ASSIGN(RpcReqSetMode, req_set_wifi_mode,
|
||||
rpc__req__set_mode__init);
|
||||
|
||||
if ((p->mode < WIFI_MODE_NULL) || (p->mode >= WIFI_MODE_MAX)) {
|
||||
ESP_LOGE(TAG, "Invalid wifi mode\n");
|
||||
*failure_status = RPC_ERR_INCORRECT_ARG;
|
||||
return FAILURE;
|
||||
}
|
||||
req_payload->mode = p->mode;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetPs: {
|
||||
wifi_power_save_t * p = &app_req->u.wifi_ps;
|
||||
RPC_ALLOC_ASSIGN(RpcReqSetPs, req_wifi_set_ps,
|
||||
rpc__req__set_ps__init);
|
||||
|
||||
req_payload->type = p->ps_mode;
|
||||
break;
|
||||
} case RPC_ID__Req_OTAWrite: {
|
||||
ota_write_t *p = & app_req->u.ota_write;
|
||||
RPC_ALLOC_ASSIGN(RpcReqOTAWrite, req_ota_write,
|
||||
rpc__req__otawrite__init);
|
||||
|
||||
if (!p->ota_data || (p->ota_data_len == 0)) {
|
||||
ESP_LOGE(TAG, "Invalid parameter\n");
|
||||
*failure_status = RPC_ERR_INCORRECT_ARG;
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
req_payload->ota_data.data = p->ota_data;
|
||||
req_payload->ota_data.len = p->ota_data_len;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetMaxTxPower: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetMaxTxPower,
|
||||
req_set_wifi_max_tx_power,
|
||||
rpc__req__wifi_set_max_tx_power__init);
|
||||
req_payload->power = app_req->u.wifi_tx_power.power;
|
||||
break;
|
||||
} case RPC_ID__Req_ConfigHeartbeat: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqConfigHeartbeat, req_config_heartbeat,
|
||||
rpc__req__config_heartbeat__init);
|
||||
req_payload->enable = app_req->u.e_heartbeat.enable;
|
||||
req_payload->duration = app_req->u.e_heartbeat.duration;
|
||||
if (req_payload->enable) {
|
||||
ESP_LOGW(TAG, "Enable heartbeat with duration %ld\n", (long int)req_payload->duration);
|
||||
if (CALLBACK_AVAILABLE != is_event_callback_registered(RPC_ID__Event_Heartbeat))
|
||||
ESP_LOGW(TAG, "Note: ** Subscribe heartbeat event to get notification **\n");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Disable Heartbeat\n");
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Req_WifiInit: {
|
||||
wifi_init_config_t * p_a = &app_req->u.wifi_init_config;
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiInit, req_wifi_init,
|
||||
rpc__req__wifi_init__init);
|
||||
RPC_ALLOC_ELEMENT(WifiInitConfig, req_payload->cfg, wifi_init_config__init);
|
||||
|
||||
req_payload->cfg->static_rx_buf_num = p_a->static_rx_buf_num ;
|
||||
req_payload->cfg->dynamic_rx_buf_num = p_a->dynamic_rx_buf_num ;
|
||||
req_payload->cfg->tx_buf_type = p_a->tx_buf_type ;
|
||||
req_payload->cfg->static_tx_buf_num = p_a->static_tx_buf_num ;
|
||||
req_payload->cfg->dynamic_tx_buf_num = p_a->dynamic_tx_buf_num ;
|
||||
req_payload->cfg->cache_tx_buf_num = p_a->cache_tx_buf_num ;
|
||||
req_payload->cfg->csi_enable = p_a->csi_enable ;
|
||||
req_payload->cfg->ampdu_rx_enable = p_a->ampdu_rx_enable ;
|
||||
req_payload->cfg->ampdu_tx_enable = p_a->ampdu_tx_enable ;
|
||||
req_payload->cfg->amsdu_tx_enable = p_a->amsdu_tx_enable ;
|
||||
req_payload->cfg->nvs_enable = p_a->nvs_enable ;
|
||||
req_payload->cfg->nano_enable = p_a->nano_enable ;
|
||||
req_payload->cfg->rx_ba_win = p_a->rx_ba_win ;
|
||||
req_payload->cfg->wifi_task_core_id = p_a->wifi_task_core_id ;
|
||||
req_payload->cfg->beacon_max_len = p_a->beacon_max_len ;
|
||||
req_payload->cfg->mgmt_sbuf_num = p_a->mgmt_sbuf_num ;
|
||||
req_payload->cfg->sta_disconnected_pm = p_a->sta_disconnected_pm ;
|
||||
req_payload->cfg->espnow_max_encrypt_num = p_a->espnow_max_encrypt_num ;
|
||||
req_payload->cfg->magic = p_a->magic ;
|
||||
|
||||
/* uint64 - TODO: portable? */
|
||||
req_payload->cfg->feature_caps = p_a->feature_caps ;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiGetConfig: {
|
||||
wifi_cfg_t * p_a = &app_req->u.wifi_config;
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiGetConfig, req_wifi_get_config,
|
||||
rpc__req__wifi_get_config__init);
|
||||
|
||||
req_payload->iface = p_a->iface;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetConfig: {
|
||||
wifi_cfg_t * p_a = &app_req->u.wifi_config;
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetConfig, req_wifi_set_config,
|
||||
rpc__req__wifi_set_config__init);
|
||||
|
||||
req_payload->iface = p_a->iface;
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiConfig, req_payload->cfg, wifi_config__init);
|
||||
|
||||
switch(req_payload->iface) {
|
||||
|
||||
case WIFI_IF_STA: {
|
||||
req_payload->cfg->u_case = WIFI_CONFIG__U_STA;
|
||||
|
||||
wifi_sta_config_t *p_a_sta = &p_a->u.sta;
|
||||
RPC_ALLOC_ELEMENT(WifiStaConfig, req_payload->cfg->sta, wifi_sta_config__init);
|
||||
WifiStaConfig *p_c_sta = req_payload->cfg->sta;
|
||||
RPC_REQ_COPY_STR(p_c_sta->ssid, p_a_sta->ssid, SSID_LENGTH);
|
||||
|
||||
RPC_REQ_COPY_STR(p_c_sta->password, p_a_sta->password, PASSWORD_LENGTH);
|
||||
|
||||
p_c_sta->scan_method = p_a_sta->scan_method;
|
||||
p_c_sta->bssid_set = p_a_sta->bssid_set;
|
||||
|
||||
if (p_a_sta->bssid_set)
|
||||
RPC_REQ_COPY_BYTES(p_c_sta->bssid, p_a_sta->bssid, BSSID_BYTES_SIZE);
|
||||
|
||||
p_c_sta->channel = p_a_sta->channel;
|
||||
p_c_sta->listen_interval = p_a_sta->listen_interval;
|
||||
p_c_sta->sort_method = p_a_sta->sort_method;
|
||||
RPC_ALLOC_ELEMENT(WifiScanThreshold, p_c_sta->threshold, wifi_scan_threshold__init);
|
||||
p_c_sta->threshold->rssi = p_a_sta->threshold.rssi;
|
||||
p_c_sta->threshold->authmode = p_a_sta->threshold.authmode;
|
||||
RPC_ALLOC_ELEMENT(WifiPmfConfig, p_c_sta->pmf_cfg, wifi_pmf_config__init);
|
||||
p_c_sta->pmf_cfg->capable = p_a_sta->pmf_cfg.capable;
|
||||
p_c_sta->pmf_cfg->required = p_a_sta->pmf_cfg.required;
|
||||
|
||||
if (p_a_sta->rm_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_rm_enabled, p_c_sta->bitmask);
|
||||
|
||||
if (p_a_sta->btm_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_btm_enabled, p_c_sta->bitmask);
|
||||
|
||||
if (p_a_sta->mbo_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_mbo_enabled, p_c_sta->bitmask);
|
||||
|
||||
if (p_a_sta->ft_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_ft_enabled, p_c_sta->bitmask);
|
||||
|
||||
if (p_a_sta->owe_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_owe_enabled, p_c_sta->bitmask);
|
||||
|
||||
if (p_a_sta->transition_disable)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_1_transition_disable, p_c_sta->bitmask);
|
||||
|
||||
#if H_WIFI_VHT_FIELDS_AVAILABLE
|
||||
if (p_a_sta->vht_su_beamformee_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_su_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->vht_mu_beamformee_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_mu_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->vht_mcs8_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_mcs8_enabled, p_c_sta->he_bitmask);
|
||||
#endif
|
||||
|
||||
#if H_DECODE_WIFI_RESERVED_FIELD
|
||||
#if H_WIFI_NEW_RESERVED_FIELD_NAMES
|
||||
WIFI_STA_CONFIG_2_SET_RESERVED_VAL(p_a_sta->reserved2, p_c_sta->he_bitmask);
|
||||
#else
|
||||
WIFI_STA_CONFIG_2_SET_RESERVED_VAL(p_a_sta->he_reserved, p_c_sta->he_bitmask);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
p_c_sta->sae_pwe_h2e = p_a_sta->sae_pwe_h2e;
|
||||
p_c_sta->failure_retry_cnt = p_a_sta->failure_retry_cnt;
|
||||
|
||||
if (p_a_sta->he_dcm_set)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_dcm_set_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
// WIFI_HE_STA_CONFIG_he_dcm_max_constellation_tx is two bits wide
|
||||
if (p_a_sta->he_dcm_max_constellation_tx)
|
||||
p_c_sta->he_bitmask |= ((p_a_sta->he_dcm_max_constellation_tx & 0x03) << WIFI_STA_CONFIG_2_he_dcm_max_constellation_tx_BITS);
|
||||
|
||||
// WIFI_HE_STA_CONFIG_he_dcm_max_constellation_rx is two bits wide
|
||||
if (p_a_sta->he_dcm_max_constellation_rx)
|
||||
p_c_sta->he_bitmask |= ((p_a_sta->he_dcm_max_constellation_rx & 0x03) << WIFI_STA_CONFIG_2_he_dcm_max_constellation_rx_BITS);
|
||||
|
||||
if (p_a_sta->he_mcs9_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_mcs9_enabled_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->he_su_beamformee_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_su_beamformee_disabled_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->he_trig_su_bmforming_feedback_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_trig_su_bmforming_feedback_disabled_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->he_trig_mu_bmforming_partial_feedback_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_trig_mu_bmforming_partial_feedback_disabled_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->he_trig_cqi_feedback_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_he_trig_cqi_feedback_disabled_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
#if H_WIFI_VHT_FIELDS_AVAILABLE
|
||||
if (p_a_sta->vht_su_beamformee_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_su_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->vht_mu_beamformee_disabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_mu_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
|
||||
if (p_a_sta->vht_mcs8_enabled)
|
||||
H_SET_BIT(WIFI_STA_CONFIG_2_vht_mcs8_enabled, p_c_sta->he_bitmask);
|
||||
#endif
|
||||
|
||||
#if H_DECODE_WIFI_RESERVED_FIELD
|
||||
#if H_WIFI_NEW_RESERVED_FIELD_NAMES
|
||||
WIFI_STA_CONFIG_2_SET_RESERVED_VAL(p_a_sta->reserved2, p_c_sta->he_bitmask);
|
||||
#else
|
||||
WIFI_STA_CONFIG_2_SET_RESERVED_VAL(p_a_sta->he_reserved, p_c_sta->he_bitmask);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RPC_REQ_COPY_BYTES(p_c_sta->sae_h2e_identifier, p_a_sta->sae_h2e_identifier, SAE_H2E_IDENTIFIER_LEN);
|
||||
break;
|
||||
} case WIFI_IF_AP: {
|
||||
req_payload->cfg->u_case = WIFI_CONFIG__U_AP;
|
||||
|
||||
wifi_ap_config_t * p_a_ap = &p_a->u.ap;
|
||||
RPC_ALLOC_ELEMENT(WifiApConfig, req_payload->cfg->ap, wifi_ap_config__init);
|
||||
WifiApConfig * p_c_ap = req_payload->cfg->ap;
|
||||
|
||||
RPC_REQ_COPY_STR(p_c_ap->ssid, p_a_ap->ssid, SSID_LENGTH);
|
||||
RPC_REQ_COPY_STR(p_c_ap->password, p_a_ap->password, PASSWORD_LENGTH);
|
||||
p_c_ap->ssid_len = p_a_ap->ssid_len;
|
||||
p_c_ap->channel = p_a_ap->channel;
|
||||
p_c_ap->authmode = p_a_ap->authmode;
|
||||
p_c_ap->ssid_hidden = p_a_ap->ssid_hidden;
|
||||
p_c_ap->max_connection = p_a_ap->max_connection;
|
||||
p_c_ap->beacon_interval = p_a_ap->beacon_interval;
|
||||
p_c_ap->pairwise_cipher = p_a_ap->pairwise_cipher;
|
||||
p_c_ap->ftm_responder = p_a_ap->ftm_responder;
|
||||
RPC_ALLOC_ELEMENT(WifiPmfConfig, p_c_ap->pmf_cfg, wifi_pmf_config__init);
|
||||
p_c_ap->pmf_cfg->capable = p_a_ap->pmf_cfg.capable;
|
||||
p_c_ap->pmf_cfg->required = p_a_ap->pmf_cfg.required;
|
||||
break;
|
||||
} default: {
|
||||
ESP_LOGE(TAG, "unexpected wifi iface [%u]\n", p_a->iface);
|
||||
break;
|
||||
}
|
||||
|
||||
} /* switch */
|
||||
break;
|
||||
|
||||
} case RPC_ID__Req_WifiScanStart: {
|
||||
wifi_scan_config_t * p_a = &app_req->u.wifi_scan_config.cfg;
|
||||
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiScanStart, req_wifi_scan_start,
|
||||
rpc__req__wifi_scan_start__init);
|
||||
|
||||
req_payload->block = app_req->u.wifi_scan_config.block;
|
||||
if (app_req->u.wifi_scan_config.cfg_set) {
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiScanConfig, req_payload->config, wifi_scan_config__init);
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiScanTime , req_payload->config->scan_time, wifi_scan_time__init);
|
||||
RPC_ALLOC_ELEMENT(WifiActiveScanTime, req_payload->config->scan_time->active, wifi_active_scan_time__init);
|
||||
ESP_LOGD(TAG, "scan start4\n");
|
||||
|
||||
WifiScanConfig *p_c = req_payload->config;
|
||||
WifiScanTime *p_c_st = NULL;
|
||||
wifi_scan_time_t *p_a_st = &p_a->scan_time;
|
||||
|
||||
RPC_REQ_COPY_STR(p_c->ssid, p_a->ssid, SSID_LENGTH);
|
||||
RPC_REQ_COPY_STR(p_c->bssid, p_a->bssid, MAC_SIZE_BYTES);
|
||||
p_c->channel = p_a->channel;
|
||||
p_c->show_hidden = p_a->show_hidden;
|
||||
p_c->scan_type = p_a->scan_type;
|
||||
|
||||
p_c_st = p_c->scan_time;
|
||||
|
||||
p_c_st->passive = p_a_st->passive;
|
||||
p_c_st->active->min = p_a_st->active.min ;
|
||||
p_c_st->active->max = p_a_st->active.max ;
|
||||
|
||||
p_c->home_chan_dwell_time = p_a->home_chan_dwell_time;
|
||||
|
||||
req_payload->config_set = 1;
|
||||
}
|
||||
ESP_LOGI(TAG, "Scan start Req\n");
|
||||
|
||||
break;
|
||||
|
||||
} case RPC_ID__Req_WifiScanGetApRecords: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiScanGetApRecords, req_wifi_scan_get_ap_records,
|
||||
rpc__req__wifi_scan_get_ap_records__init);
|
||||
req_payload->number = app_req->u.wifi_scan_ap_list.number;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiDeauthSta: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiDeauthSta, req_wifi_deauth_sta,
|
||||
rpc__req__wifi_deauth_sta__init);
|
||||
req_payload->aid = app_req->u.wifi_deauth_sta.aid;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetStorage: {
|
||||
wifi_storage_t * p = &app_req->u.wifi_storage;
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetStorage, req_wifi_set_storage,
|
||||
rpc__req__wifi_set_storage__init);
|
||||
req_payload->storage = *p;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetBandwidth: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetBandwidth, req_wifi_set_bandwidth,
|
||||
rpc__req__wifi_set_bandwidth__init);
|
||||
req_payload->ifx = app_req->u.wifi_bandwidth.ifx;
|
||||
req_payload->bw = app_req->u.wifi_bandwidth.bw;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiGetBandwidth: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiGetBandwidth, req_wifi_get_bandwidth,
|
||||
rpc__req__wifi_get_bandwidth__init);
|
||||
req_payload->ifx = app_req->u.wifi_bandwidth.ifx;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetChannel: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetChannel, req_wifi_set_channel,
|
||||
rpc__req__wifi_set_channel__init);
|
||||
req_payload->primary = app_req->u.wifi_channel.primary;
|
||||
req_payload->second = app_req->u.wifi_channel.second;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetCountryCode: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetCountryCode, req_wifi_set_country_code,
|
||||
rpc__req__wifi_set_country_code__init);
|
||||
RPC_REQ_COPY_BYTES(req_payload->country, (uint8_t *)&app_req->u.wifi_country_code.cc[0], sizeof(app_req->u.wifi_country_code.cc));
|
||||
req_payload->ieee80211d_enabled = app_req->u.wifi_country_code.ieee80211d_enabled;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetCountry: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetCountry, req_wifi_set_country,
|
||||
rpc__req__wifi_set_country__init);
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiCountry, req_payload->country, wifi_country__init);
|
||||
RPC_REQ_COPY_BYTES(req_payload->country->cc, (uint8_t *)&app_req->u.wifi_country.cc[0], sizeof(app_req->u.wifi_country.cc));
|
||||
req_payload->country->schan = app_req->u.wifi_country.schan;
|
||||
req_payload->country->nchan = app_req->u.wifi_country.nchan;
|
||||
req_payload->country->max_tx_power = app_req->u.wifi_country.max_tx_power;
|
||||
req_payload->country->policy = app_req->u.wifi_country.policy;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiApGetStaAid: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiApGetStaAid, req_wifi_ap_get_sta_aid,
|
||||
rpc__req__wifi_ap_get_sta_aid__init);
|
||||
|
||||
uint8_t * p = &app_req->u.wifi_ap_get_sta_aid.mac[0];
|
||||
RPC_REQ_COPY_BYTES(req_payload->mac, p, MAC_SIZE_BYTES);
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetProtocol: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetProtocol, req_wifi_set_protocol,
|
||||
rpc__req__wifi_set_protocol__init);
|
||||
req_payload->ifx = app_req->u.wifi_protocol.ifx;
|
||||
req_payload->protocol_bitmap = app_req->u.wifi_protocol.protocol_bitmap;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiGetProtocol: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiGetProtocol, req_wifi_get_protocol,
|
||||
rpc__req__wifi_get_protocol__init);
|
||||
req_payload->ifx = app_req->u.wifi_protocol.ifx;
|
||||
break;
|
||||
} case RPC_ID__Req_GetCoprocessorFwVersion: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqGetCoprocessorFwVersion, req_get_coprocessor_fwversion,
|
||||
rpc__req__get_coprocessor_fw_version__init);
|
||||
break;
|
||||
#if H_WIFI_DUALBAND_SUPPORT
|
||||
} case RPC_ID__Req_WifiSetProtocols: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetProtocols, req_wifi_set_protocols,
|
||||
rpc__req__wifi_set_protocols__init);
|
||||
req_payload->ifx = app_req->u.wifi_protocols.ifx;
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiProtocols, req_payload->protocols, wifi_protocols__init);
|
||||
req_payload->protocols->ghz_2g = app_req->u.wifi_protocols.ghz_2g;
|
||||
req_payload->protocols->ghz_5g = app_req->u.wifi_protocols.ghz_5g;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiGetProtocols: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiGetProtocols, req_wifi_get_protocols,
|
||||
rpc__req__wifi_get_protocols__init);
|
||||
req_payload->ifx = app_req->u.wifi_protocols.ifx;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetBandwidths: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetBandwidths, req_wifi_set_bandwidths,
|
||||
rpc__req__wifi_set_bandwidths__init);
|
||||
req_payload->ifx = app_req->u.wifi_bandwidths.ifx;
|
||||
|
||||
RPC_ALLOC_ELEMENT(WifiBandwidths, req_payload->bandwidths, wifi_bandwidths__init);
|
||||
req_payload->bandwidths->ghz_2g = app_req->u.wifi_bandwidths.ghz_2g;
|
||||
req_payload->bandwidths->ghz_5g = app_req->u.wifi_bandwidths.ghz_5g;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiGetBandwidths: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiGetBandwidths, req_wifi_get_bandwidths,
|
||||
rpc__req__wifi_get_bandwidths__init);
|
||||
req_payload->ifx = app_req->u.wifi_bandwidths.ifx;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetBand: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetBand, req_wifi_set_band,
|
||||
rpc__req__wifi_set_band__init);
|
||||
req_payload->band = app_req->u.wifi_band;
|
||||
break;
|
||||
} case RPC_ID__Req_WifiSetBandMode: {
|
||||
RPC_ALLOC_ASSIGN(RpcReqWifiSetBandMode, req_wifi_set_bandmode,
|
||||
rpc__req__wifi_set_band_mode__init);
|
||||
req_payload->bandmode = app_req->u.wifi_band_mode;
|
||||
break;
|
||||
#endif
|
||||
} default: {
|
||||
*failure_status = RPC_ERR_UNSUPPORTED_MSG;
|
||||
ESP_LOGE(TAG, "Unsupported RPC Req[%u]",req->msg_id);
|
||||
return FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
} /* switch */
|
||||
return SUCCESS;
|
||||
}
|
||||
624
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_rsp.c
Normal file
624
resources/espressif__esp_hosted/host/drivers/rpc/core/rpc_rsp.c
Normal file
@@ -0,0 +1,624 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
|
||||
|
||||
#include "rpc_core.h"
|
||||
#include "rpc_slave_if.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_wifi_config.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_bitmasks.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_hosted_config.h"
|
||||
|
||||
DEFINE_LOG_TAG(rpc_rsp);
|
||||
|
||||
/* RPC response is result of remote function invokation at slave from host
|
||||
* The response will contain the return values of the RPC procedure
|
||||
* Return values typically will be simple integer return value of rpc call
|
||||
* for simple procedures. For function call with return value as a parameter,
|
||||
* RPC will contain full structure returned for that parameter and wrapper
|
||||
* level above will return these in expected pointer
|
||||
*
|
||||
* Responses will typically have two levels:
|
||||
* 1. protobuf level response received
|
||||
* 2. parse the response so that Ctrl_cmd_t app structure will be populated
|
||||
* or parsed from protobuf level response.
|
||||
*
|
||||
* For new RPC request, add up switch case for your message
|
||||
* For altogether new RPC function addition, please check
|
||||
* esp_hosted_fg/common/proto/esp_hosted_config.proto as a start point
|
||||
*/
|
||||
|
||||
#define RPC_ERR_IN_RESP(msGparaM) \
|
||||
if (rpc_msg->msGparaM->resp) { \
|
||||
app_resp->resp_event_status = rpc_msg->msGparaM->resp; \
|
||||
ESP_LOGW(TAG, "Hosted RPC_Resp [0x%"PRIx16"], uid [%"PRIu32"], resp code [%"PRIi32"]", \
|
||||
app_resp->msg_id, app_resp->uid, app_resp->resp_event_status); \
|
||||
goto fail_parse_rpc_msg; \
|
||||
}
|
||||
|
||||
|
||||
#define RPC_RSP_COPY_BYTES(dst,src) { \
|
||||
if (src.data && src.len) { \
|
||||
g_h.funcs->_h_memcpy(dst, src.data, src.len); \
|
||||
} \
|
||||
}
|
||||
|
||||
// copy the rpc record info to the wifi record info
|
||||
static int rpc_copy_ap_record(wifi_ap_record_t *ap_record, WifiApRecord *rpc_ap_record)
|
||||
{
|
||||
RPC_RSP_COPY_BYTES(ap_record->ssid, rpc_ap_record->ssid);
|
||||
RPC_RSP_COPY_BYTES(ap_record->bssid, rpc_ap_record->bssid);
|
||||
|
||||
ap_record->primary = rpc_ap_record->primary;
|
||||
ap_record->second = rpc_ap_record->second;
|
||||
ap_record->rssi = rpc_ap_record->rssi;
|
||||
ap_record->authmode = rpc_ap_record->authmode;
|
||||
ap_record->pairwise_cipher = rpc_ap_record->pairwise_cipher;
|
||||
ap_record->group_cipher = rpc_ap_record->group_cipher;
|
||||
ap_record->ant = rpc_ap_record->ant;
|
||||
|
||||
ap_record->phy_11b = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11b_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_11g = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11g_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_11n = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11n_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_lr = H_GET_BIT(WIFI_SCAN_AP_REC_phy_lr_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_11a = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11a_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_11ac = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11ac_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->phy_11ax = H_GET_BIT(WIFI_SCAN_AP_REC_phy_11ax_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->wps = H_GET_BIT(WIFI_SCAN_AP_REC_wps_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->ftm_responder = H_GET_BIT(WIFI_SCAN_AP_REC_ftm_responder_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->ftm_initiator = H_GET_BIT(WIFI_SCAN_AP_REC_ftm_initiator_BIT, rpc_ap_record->bitmask);
|
||||
ap_record->reserved = WIFI_SCAN_AP_GET_RESERVED_VAL(rpc_ap_record->bitmask);
|
||||
|
||||
RPC_RSP_COPY_BYTES(ap_record->country.cc, rpc_ap_record->country->cc);
|
||||
ap_record->country.schan = rpc_ap_record->country->schan;
|
||||
ap_record->country.nchan = rpc_ap_record->country->nchan;
|
||||
ap_record->country.max_tx_power = rpc_ap_record->country->max_tx_power;
|
||||
ap_record->country.policy = rpc_ap_record->country->policy;
|
||||
|
||||
ESP_LOGD(TAG, "SSID: %s BSSid: " MACSTR, ap_record->ssid, MAC2STR(ap_record->bssid));
|
||||
ESP_LOGD(TAG, "Primary: %u Second: %u RSSI: %d Authmode: %u",
|
||||
ap_record->primary, ap_record->second,
|
||||
ap_record->rssi, ap_record->authmode
|
||||
);
|
||||
ESP_LOGD(TAG, "PairwiseCipher: %u Groupcipher: %u Ant: %u",
|
||||
ap_record->pairwise_cipher, ap_record->group_cipher,
|
||||
ap_record->ant
|
||||
);
|
||||
ESP_LOGD(TAG, "Bitmask: 11b:%u g:%u n:%u ax: %u lr:%u wps:%u ftm_resp:%u ftm_ini:%u res: %u",
|
||||
ap_record->phy_11b, ap_record->phy_11g,
|
||||
ap_record->phy_11n, ap_record->phy_11ax, ap_record->phy_lr,
|
||||
ap_record->wps, ap_record->ftm_responder,
|
||||
ap_record->ftm_initiator, ap_record->reserved
|
||||
);
|
||||
ESP_LOGD(TAG, "Country cc:%c%c schan: %u nchan: %u max_tx_pow: %d policy: %u",
|
||||
ap_record->country.cc[0], ap_record->country.cc[1], ap_record->country.schan,
|
||||
ap_record->country.nchan, ap_record->country.max_tx_power,
|
||||
ap_record->country.policy);
|
||||
|
||||
WifiHeApInfo *p_c_he_ap = rpc_ap_record->he_ap;
|
||||
wifi_he_ap_info_t *p_a_he_ap = &ap_record->he_ap;
|
||||
// six bits
|
||||
p_a_he_ap->bss_color = p_c_he_ap->bitmask & 0x3F;
|
||||
p_a_he_ap->partial_bss_color = H_GET_BIT(WIFI_HE_AP_INFO_partial_bss_color_BIT, p_c_he_ap->bitmask);
|
||||
p_a_he_ap->bss_color_disabled = H_GET_BIT(WIFI_HE_AP_INFO_bss_color_disabled_BIT, p_c_he_ap->bitmask);
|
||||
|
||||
ESP_LOGD(TAG, "HE_AP: bss_color %d, partial_bss_color %d, bss_color_disabled %d",
|
||||
p_a_he_ap->bss_color, p_a_he_ap->bss_color_disabled, p_a_he_ap->bss_color_disabled);
|
||||
|
||||
ap_record->bandwidth = rpc_ap_record->bandwidth;
|
||||
ap_record->vht_ch_freq1 = rpc_ap_record->vht_ch_freq1;
|
||||
ap_record->vht_ch_freq2 = rpc_ap_record->vht_ch_freq2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This will copy rpc response from `Rpc` into
|
||||
* application structure `ctrl_cmd_t`
|
||||
* This function is called after protobuf decoding is successful
|
||||
**/
|
||||
int rpc_parse_rsp(Rpc *rpc_msg, ctrl_cmd_t *app_resp)
|
||||
{
|
||||
uint16_t i = 0;
|
||||
|
||||
/* 1. Check non NULL */
|
||||
if (!rpc_msg || !app_resp) {
|
||||
ESP_LOGE(TAG, "NULL rpc resp or NULL App Resp");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
|
||||
/* 2. update basic fields */
|
||||
app_resp->msg_type = RPC_TYPE__Resp;
|
||||
app_resp->msg_id = rpc_msg->msg_id;
|
||||
app_resp->uid = rpc_msg->uid;
|
||||
ESP_LOGI(TAG, " --> RPC_Resp [0x%x], uid %ld", app_resp->msg_id, app_resp->uid);
|
||||
|
||||
/* 3. parse Rpc into ctrl_cmd_t */
|
||||
switch (rpc_msg->msg_id) {
|
||||
|
||||
case RPC_ID__Resp_GetMACAddress : {
|
||||
RPC_FAIL_ON_NULL(resp_get_mac_address);
|
||||
RPC_ERR_IN_RESP(resp_get_mac_address);
|
||||
RPC_FAIL_ON_NULL(resp_get_mac_address->mac.data);
|
||||
|
||||
RPC_RSP_COPY_BYTES(app_resp->u.wifi_mac.mac, rpc_msg->resp_get_mac_address->mac);
|
||||
ESP_LOGD(TAG, "Mac addr: "MACSTR, MAC2STR(app_resp->u.wifi_mac.mac));
|
||||
break;
|
||||
} case RPC_ID__Resp_SetMacAddress : {
|
||||
RPC_FAIL_ON_NULL(resp_set_mac_address);
|
||||
RPC_ERR_IN_RESP(resp_set_mac_address);
|
||||
break;
|
||||
} case RPC_ID__Resp_GetWifiMode : {
|
||||
RPC_FAIL_ON_NULL(resp_get_wifi_mode);
|
||||
RPC_ERR_IN_RESP(resp_get_wifi_mode);
|
||||
|
||||
app_resp->u.wifi_mode.mode = rpc_msg->resp_get_wifi_mode->mode;
|
||||
break;
|
||||
} case RPC_ID__Resp_SetWifiMode : {
|
||||
RPC_FAIL_ON_NULL(resp_set_wifi_mode);
|
||||
RPC_ERR_IN_RESP(resp_set_wifi_mode);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetPs: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_ps);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_ps);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetPs : {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_ps);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_ps);
|
||||
app_resp->u.wifi_ps.ps_mode = rpc_msg->resp_wifi_get_ps->type;
|
||||
break;
|
||||
} case RPC_ID__Resp_OTABegin : {
|
||||
RPC_FAIL_ON_NULL(resp_ota_begin);
|
||||
RPC_ERR_IN_RESP(resp_ota_begin);
|
||||
if (rpc_msg->resp_ota_begin->resp) {
|
||||
ESP_LOGE(TAG, "OTA Begin Failed");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Resp_OTAWrite : {
|
||||
RPC_FAIL_ON_NULL(resp_ota_write);
|
||||
RPC_ERR_IN_RESP(resp_ota_write);
|
||||
if (rpc_msg->resp_ota_write->resp) {
|
||||
ESP_LOGE(TAG, "OTA write failed");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Resp_OTAEnd: {
|
||||
RPC_FAIL_ON_NULL(resp_ota_end);
|
||||
if (rpc_msg->resp_ota_end->resp) {
|
||||
ESP_LOGE(TAG, "OTA write failed");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetMaxTxPower: {
|
||||
RPC_FAIL_ON_NULL(resp_set_wifi_max_tx_power);
|
||||
RPC_ERR_IN_RESP(resp_set_wifi_max_tx_power);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetMaxTxPower: {
|
||||
RPC_FAIL_ON_NULL(resp_get_wifi_max_tx_power);
|
||||
RPC_ERR_IN_RESP(resp_get_wifi_max_tx_power);
|
||||
app_resp->u.wifi_tx_power.power =
|
||||
rpc_msg->resp_get_wifi_max_tx_power->power;
|
||||
break;
|
||||
} case RPC_ID__Resp_ConfigHeartbeat: {
|
||||
RPC_FAIL_ON_NULL(resp_config_heartbeat);
|
||||
RPC_ERR_IN_RESP(resp_config_heartbeat);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiInit: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_init);
|
||||
RPC_ERR_IN_RESP(resp_wifi_init);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiDeinit: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_deinit);
|
||||
RPC_ERR_IN_RESP(resp_wifi_deinit);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStart: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_start);
|
||||
RPC_ERR_IN_RESP(resp_wifi_start);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStop: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_stop);
|
||||
RPC_ERR_IN_RESP(resp_wifi_stop);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiConnect: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_connect);
|
||||
RPC_ERR_IN_RESP(resp_wifi_connect);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiDisconnect: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_disconnect);
|
||||
RPC_ERR_IN_RESP(resp_wifi_disconnect);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetConfig: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_config);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_config);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetConfig: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_config);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_config);
|
||||
|
||||
app_resp->u.wifi_config.iface = rpc_msg->resp_wifi_get_config->iface;
|
||||
|
||||
switch (app_resp->u.wifi_config.iface) {
|
||||
|
||||
case WIFI_IF_STA: {
|
||||
wifi_sta_config_t * p_a_sta = &(app_resp->u.wifi_config.u.sta);
|
||||
WifiStaConfig * p_c_sta = rpc_msg->resp_wifi_get_config->cfg->sta;
|
||||
RPC_RSP_COPY_BYTES(p_a_sta->ssid, p_c_sta->ssid);
|
||||
RPC_RSP_COPY_BYTES(p_a_sta->password, p_c_sta->password);
|
||||
p_a_sta->scan_method = p_c_sta->scan_method;
|
||||
p_a_sta->bssid_set = p_c_sta->bssid_set;
|
||||
|
||||
if (p_a_sta->bssid_set)
|
||||
RPC_RSP_COPY_BYTES(p_a_sta->bssid, p_c_sta->bssid);
|
||||
|
||||
p_a_sta->channel = p_c_sta->channel;
|
||||
p_a_sta->listen_interval = p_c_sta->listen_interval;
|
||||
p_a_sta->sort_method = p_c_sta->sort_method;
|
||||
p_a_sta->threshold.rssi = p_c_sta->threshold->rssi;
|
||||
p_a_sta->threshold.authmode = p_c_sta->threshold->authmode;
|
||||
//p_a_sta->ssid_hidden = p_c_sta->ssid_hidden;
|
||||
//p_a_sta->max_connections = p_c_sta->max_connections;
|
||||
p_a_sta->pmf_cfg.capable = p_c_sta->pmf_cfg->capable;
|
||||
p_a_sta->pmf_cfg.required = p_c_sta->pmf_cfg->required;
|
||||
|
||||
p_a_sta->rm_enabled = H_GET_BIT(WIFI_STA_CONFIG_1_rm_enabled, p_c_sta->bitmask);
|
||||
p_a_sta->btm_enabled = H_GET_BIT(WIFI_STA_CONFIG_1_btm_enabled, p_c_sta->bitmask);
|
||||
p_a_sta->mbo_enabled = H_GET_BIT(WIFI_STA_CONFIG_1_mbo_enabled, p_c_sta->bitmask);
|
||||
p_a_sta->ft_enabled = H_GET_BIT(WIFI_STA_CONFIG_1_ft_enabled, p_c_sta->bitmask);
|
||||
p_a_sta->owe_enabled = H_GET_BIT(WIFI_STA_CONFIG_1_owe_enabled, p_c_sta->bitmask);
|
||||
p_a_sta->transition_disable = H_GET_BIT(WIFI_STA_CONFIG_1_transition_disable, p_c_sta->bitmask);
|
||||
|
||||
#if H_DECODE_WIFI_RESERVED_FIELD
|
||||
#if H_WIFI_NEW_RESERVED_FIELD_NAMES
|
||||
p_a_sta->reserved1 = WIFI_STA_CONFIG_1_GET_RESERVED_VAL(p_c_sta->bitmask);
|
||||
#else
|
||||
p_a_sta->reserved = WIFI_STA_CONFIG_1_GET_RESERVED_VAL(p_c_sta->bitmask);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
p_a_sta->sae_pwe_h2e = p_c_sta->sae_pwe_h2e;
|
||||
p_a_sta->failure_retry_cnt = p_c_sta->failure_retry_cnt;
|
||||
|
||||
p_a_sta->he_dcm_set = H_GET_BIT(WIFI_STA_CONFIG_2_he_dcm_set_BIT, p_c_sta->he_bitmask);
|
||||
|
||||
// WIFI_HE_STA_CONFIG_he_dcm_max_constellation_tx is two bits wide
|
||||
p_a_sta->he_dcm_max_constellation_tx = (p_c_sta->he_bitmask >> WIFI_STA_CONFIG_2_he_dcm_max_constellation_tx_BITS) & 0x03;
|
||||
// WIFI_HE_STA_CONFIG_he_dcm_max_constellation_rx is two bits wide
|
||||
p_a_sta->he_dcm_max_constellation_rx = (p_c_sta->he_bitmask >> WIFI_STA_CONFIG_2_he_dcm_max_constellation_rx_BITS) & 0x03;
|
||||
p_a_sta->he_mcs9_enabled = H_GET_BIT(WIFI_STA_CONFIG_2_he_mcs9_enabled_BIT, p_c_sta->he_bitmask);
|
||||
p_a_sta->he_su_beamformee_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_he_su_beamformee_disabled_BIT, p_c_sta->he_bitmask);
|
||||
p_a_sta->he_trig_su_bmforming_feedback_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_he_trig_su_bmforming_feedback_disabled_BIT, p_c_sta->bitmask);
|
||||
p_a_sta->he_trig_mu_bmforming_partial_feedback_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_he_trig_mu_bmforming_partial_feedback_disabled_BIT, p_c_sta->bitmask);
|
||||
p_a_sta->he_trig_cqi_feedback_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_he_trig_cqi_feedback_disabled_BIT, p_c_sta->bitmask);
|
||||
|
||||
#if H_WIFI_VHT_FIELDS_AVAILABLE
|
||||
p_a_sta->vht_su_beamformee_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_vht_su_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
p_a_sta->vht_mu_beamformee_disabled = H_GET_BIT(WIFI_STA_CONFIG_2_vht_mu_beamformee_disabled, p_c_sta->he_bitmask);
|
||||
p_a_sta->vht_mcs8_enabled = H_GET_BIT(WIFI_STA_CONFIG_2_vht_mcs8_enabled, p_c_sta->he_bitmask);
|
||||
#endif
|
||||
|
||||
#if H_DECODE_WIFI_RESERVED_FIELD
|
||||
#if H_WIFI_NEW_RESERVED_FIELD_NAMES
|
||||
p_a_sta->reserved2 = WIFI_STA_CONFIG_2_GET_RESERVED_VAL(p_c_sta->he_bitmask);
|
||||
#else
|
||||
p_a_sta->he_reserved = WIFI_STA_CONFIG_2_GET_RESERVED_VAL(p_c_sta->he_bitmask);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
case WIFI_IF_AP: {
|
||||
wifi_ap_config_t * p_a_ap = &(app_resp->u.wifi_config.u.ap);
|
||||
WifiApConfig * p_c_ap = rpc_msg->resp_wifi_get_config->cfg->ap;
|
||||
|
||||
RPC_RSP_COPY_BYTES(p_a_ap->ssid, p_c_ap->ssid);
|
||||
RPC_RSP_COPY_BYTES(p_a_ap->password, p_c_ap->password);
|
||||
p_a_ap->ssid_len = p_c_ap->ssid_len;
|
||||
p_a_ap->channel = p_c_ap->channel;
|
||||
p_a_ap->authmode = p_c_ap->authmode;
|
||||
p_a_ap->ssid_hidden = p_c_ap->ssid_hidden;
|
||||
p_a_ap->max_connection = p_c_ap->max_connection;
|
||||
p_a_ap->beacon_interval = p_c_ap->beacon_interval;
|
||||
p_a_ap->pairwise_cipher = p_c_ap->pairwise_cipher;
|
||||
p_a_ap->ftm_responder = p_c_ap->ftm_responder;
|
||||
p_a_ap->pmf_cfg.capable = p_c_ap->pmf_cfg->capable;
|
||||
p_a_ap->pmf_cfg.required = p_c_ap->pmf_cfg->required;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported WiFi interface[%u]", app_resp->u.wifi_config.iface);
|
||||
} //switch
|
||||
|
||||
break;
|
||||
|
||||
} case RPC_ID__Resp_WifiScanStart: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_start);
|
||||
RPC_ERR_IN_RESP(resp_wifi_scan_start);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiScanStop: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_stop);
|
||||
RPC_ERR_IN_RESP(resp_wifi_scan_stop);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiScanGetApNum: {
|
||||
wifi_scan_ap_list_t *p_a = &(app_resp->u.wifi_scan_ap_list);
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_get_ap_num);
|
||||
RPC_ERR_IN_RESP(resp_wifi_scan_get_ap_num);
|
||||
|
||||
p_a->number = rpc_msg->resp_wifi_scan_get_ap_num->number;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiScanGetApRecord: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_get_ap_records);
|
||||
RPC_ERR_IN_RESP(resp_wifi_scan_get_ap_records);
|
||||
|
||||
rpc_copy_ap_record(&(app_resp->u.wifi_ap_record),
|
||||
rpc_msg->resp_wifi_scan_get_ap_record->ap_record);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiScanGetApRecords: {
|
||||
wifi_scan_ap_list_t *p_a = &(app_resp->u.wifi_scan_ap_list);
|
||||
wifi_ap_record_t *list = NULL;
|
||||
WifiApRecord **p_c_list = NULL;
|
||||
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_get_ap_records);
|
||||
RPC_ERR_IN_RESP(resp_wifi_scan_get_ap_records);
|
||||
p_c_list = rpc_msg->resp_wifi_scan_get_ap_records->ap_records;
|
||||
|
||||
p_a->number = rpc_msg->resp_wifi_scan_get_ap_records->number;
|
||||
|
||||
if (!p_a->number) {
|
||||
ESP_LOGI(TAG, "No AP found");
|
||||
goto fail_parse_rpc_msg;
|
||||
}
|
||||
ESP_LOGD(TAG, "Num AP records: %u",
|
||||
app_resp->u.wifi_scan_ap_list.number);
|
||||
|
||||
RPC_FAIL_ON_NULL(resp_wifi_scan_get_ap_records->ap_records);
|
||||
|
||||
list = (wifi_ap_record_t*)g_h.funcs->_h_calloc(p_a->number,
|
||||
sizeof(wifi_ap_record_t));
|
||||
p_a->out_list = list;
|
||||
|
||||
RPC_FAIL_ON_NULL_PRINT(list, "Malloc Failed");
|
||||
|
||||
app_resp->app_free_buff_func = g_h.funcs->_h_free;
|
||||
app_resp->app_free_buff_hdl = list;
|
||||
|
||||
ESP_LOGD(TAG, "Number of available APs is %d", p_a->number);
|
||||
for (i=0; i<p_a->number; i++) {
|
||||
rpc_copy_ap_record(&list[i], p_c_list[i]);
|
||||
}
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStaGetApInfo: {
|
||||
WifiApRecord *p_c = NULL;
|
||||
wifi_ap_record_t *ap_info = NULL;
|
||||
wifi_scan_ap_list_t *p_a = &(app_resp->u.wifi_scan_ap_list);
|
||||
|
||||
RPC_FAIL_ON_NULL(resp_wifi_sta_get_ap_info);
|
||||
RPC_ERR_IN_RESP(resp_wifi_sta_get_ap_info);
|
||||
p_c = rpc_msg->resp_wifi_sta_get_ap_info->ap_record;
|
||||
|
||||
p_a->number = 1;
|
||||
|
||||
RPC_FAIL_ON_NULL(resp_wifi_sta_get_ap_info->ap_record);
|
||||
|
||||
ap_info = (wifi_ap_record_t*)g_h.funcs->_h_calloc(p_a->number,
|
||||
sizeof(wifi_ap_record_t));
|
||||
p_a->out_list = ap_info;
|
||||
|
||||
RPC_FAIL_ON_NULL_PRINT(ap_info, "Malloc Failed");
|
||||
|
||||
app_resp->app_free_buff_func = g_h.funcs->_h_free;
|
||||
app_resp->app_free_buff_hdl = ap_info;
|
||||
|
||||
rpc_copy_ap_record(ap_info, p_c);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiClearApList: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_clear_ap_list);
|
||||
RPC_ERR_IN_RESP(resp_wifi_clear_ap_list);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiRestore: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_restore);
|
||||
RPC_ERR_IN_RESP(resp_wifi_restore);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiClearFastConnect: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_clear_fast_connect);
|
||||
RPC_ERR_IN_RESP(resp_wifi_clear_fast_connect);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiDeauthSta: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_deauth_sta);
|
||||
RPC_ERR_IN_RESP(resp_wifi_deauth_sta);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetStorage: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_storage);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_storage);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetBandwidth: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_bandwidth);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_bandwidth);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetBandwidth: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_bandwidth);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_bandwidth);
|
||||
app_resp->u.wifi_bandwidth.bw =
|
||||
rpc_msg->resp_wifi_get_bandwidth->bw;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetChannel: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_channel);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_channel);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetChannel: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_channel);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_channel);
|
||||
app_resp->u.wifi_channel.primary =
|
||||
rpc_msg->resp_wifi_get_channel->primary;
|
||||
app_resp->u.wifi_channel.second =
|
||||
rpc_msg->resp_wifi_get_channel->second;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetCountryCode: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_country_code);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_country_code);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetCountryCode: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_country_code);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_country_code);
|
||||
|
||||
RPC_RSP_COPY_BYTES(&app_resp->u.wifi_country_code.cc[0],
|
||||
rpc_msg->resp_wifi_get_country_code->country);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetCountry: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_country);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_country);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetCountry: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_country);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_country);
|
||||
|
||||
RPC_RSP_COPY_BYTES(&app_resp->u.wifi_country.cc[0],
|
||||
rpc_msg->resp_wifi_get_country->country->cc);
|
||||
app_resp->u.wifi_country.schan = rpc_msg->resp_wifi_get_country->country->schan;
|
||||
app_resp->u.wifi_country.nchan = rpc_msg->resp_wifi_get_country->country->nchan;
|
||||
app_resp->u.wifi_country.max_tx_power = rpc_msg->resp_wifi_get_country->country->max_tx_power;
|
||||
app_resp->u.wifi_country.policy = rpc_msg->resp_wifi_get_country->country->policy;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiApGetStaList: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_ap_get_sta_list);
|
||||
RPC_ERR_IN_RESP(resp_wifi_ap_get_sta_list);
|
||||
|
||||
// handle case where slave's num is bigger than our ESP_WIFI_MAX_CONN_NUM
|
||||
uint32_t num_stations = rpc_msg->resp_wifi_ap_get_sta_list->sta_list->num;
|
||||
if (num_stations > ESP_WIFI_MAX_CONN_NUM) {
|
||||
ESP_LOGW(TAG, "Slave returned %ld connected stations, but we can only accept %d items", num_stations, ESP_WIFI_MAX_CONN_NUM);
|
||||
num_stations = ESP_WIFI_MAX_CONN_NUM;
|
||||
}
|
||||
|
||||
WifiStaInfo ** p_c_sta_list = rpc_msg->resp_wifi_ap_get_sta_list->sta_list->sta;
|
||||
|
||||
for (int i = 0; i < num_stations; i++) {
|
||||
wifi_sta_info_t * p_a_sta = &app_resp->u.wifi_ap_sta_list.sta[i];
|
||||
|
||||
RPC_RSP_COPY_BYTES(p_a_sta->mac, p_c_sta_list[i]->mac);
|
||||
p_a_sta->rssi = p_c_sta_list[i]->rssi;
|
||||
|
||||
p_a_sta->phy_11b = H_GET_BIT(WIFI_STA_INFO_phy_11b_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->phy_11g = H_GET_BIT(WIFI_STA_INFO_phy_11g_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->phy_11n = H_GET_BIT(WIFI_STA_INFO_phy_11n_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->phy_lr = H_GET_BIT(WIFI_STA_INFO_phy_lr_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->phy_11ax = H_GET_BIT(WIFI_STA_INFO_phy_11ax_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->is_mesh_child = H_GET_BIT(WIFI_STA_INFO_is_mesh_child_BIT, p_c_sta_list[i]->bitmask);
|
||||
p_a_sta->reserved = WIFI_STA_INFO_GET_RESERVED_VAL(p_c_sta_list[i]->bitmask);
|
||||
}
|
||||
|
||||
app_resp->u.wifi_ap_sta_list.num = rpc_msg->resp_wifi_ap_get_sta_list->sta_list->num;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiApGetStaAid: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_ap_get_sta_aid);
|
||||
RPC_ERR_IN_RESP(resp_wifi_ap_get_sta_aid);
|
||||
|
||||
app_resp->u.wifi_ap_get_sta_aid.aid = rpc_msg->resp_wifi_ap_get_sta_aid->aid;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStaGetRssi: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_sta_get_rssi);
|
||||
RPC_ERR_IN_RESP(resp_wifi_sta_get_rssi);
|
||||
|
||||
app_resp->u.wifi_sta_get_rssi.rssi = rpc_msg->resp_wifi_sta_get_rssi->rssi;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetProtocol: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_protocol);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_protocol);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetProtocol: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_protocol);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_protocol);
|
||||
app_resp->u.wifi_protocol.protocol_bitmap =
|
||||
rpc_msg->resp_wifi_get_protocol->protocol_bitmap;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStaGetNegotiatedPhymode: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_sta_get_negotiated_phymode);
|
||||
RPC_ERR_IN_RESP(resp_wifi_sta_get_negotiated_phymode);
|
||||
app_resp->u.wifi_sta_get_negotiated_phymode.phymode =
|
||||
rpc_msg->resp_wifi_sta_get_negotiated_phymode->phymode;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiStaGetAid: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_sta_get_aid);
|
||||
RPC_ERR_IN_RESP(resp_wifi_sta_get_aid);
|
||||
app_resp->u.wifi_sta_get_aid.aid =
|
||||
rpc_msg->resp_wifi_sta_get_aid->aid;
|
||||
break;
|
||||
} case RPC_ID__Resp_GetCoprocessorFwVersion: {
|
||||
RPC_FAIL_ON_NULL(resp_get_coprocessor_fwversion);
|
||||
RPC_ERR_IN_RESP(resp_get_coprocessor_fwversion);
|
||||
app_resp->u.coprocessor_fwversion.major1 =
|
||||
rpc_msg->resp_get_coprocessor_fwversion->major1;
|
||||
app_resp->u.coprocessor_fwversion.minor1 =
|
||||
rpc_msg->resp_get_coprocessor_fwversion->minor1;
|
||||
app_resp->u.coprocessor_fwversion.patch1 =
|
||||
rpc_msg->resp_get_coprocessor_fwversion->patch1;
|
||||
break;
|
||||
#if H_WIFI_DUALBAND_SUPPORT
|
||||
} case RPC_ID__Resp_WifiSetProtocols: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_protocols);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_protocols);
|
||||
app_resp->u.wifi_protocols.ifx =
|
||||
rpc_msg->resp_wifi_set_protocols->ifx;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetProtocols: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_protocols);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_protocols);
|
||||
app_resp->u.wifi_protocols.ifx =
|
||||
rpc_msg->resp_wifi_get_protocols->ifx;
|
||||
app_resp->u.wifi_protocols.ghz_2g =
|
||||
rpc_msg->resp_wifi_get_protocols->protocols->ghz_2g;
|
||||
app_resp->u.wifi_protocols.ghz_5g =
|
||||
rpc_msg->resp_wifi_get_protocols->protocols->ghz_5g;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetBandwidths: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_bandwidths);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_bandwidths);
|
||||
app_resp->u.wifi_bandwidths.ifx =
|
||||
rpc_msg->resp_wifi_set_bandwidths->ifx;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetBandwidths: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_bandwidths);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_bandwidths);
|
||||
app_resp->u.wifi_bandwidths.ifx =
|
||||
rpc_msg->resp_wifi_get_bandwidths->ifx;
|
||||
app_resp->u.wifi_bandwidths.ghz_2g =
|
||||
rpc_msg->resp_wifi_get_bandwidths->bandwidths->ghz_2g;
|
||||
app_resp->u.wifi_bandwidths.ghz_5g =
|
||||
rpc_msg->resp_wifi_get_bandwidths->bandwidths->ghz_5g;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetBand: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_country_code);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_country_code);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetBand: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_band);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_band);
|
||||
app_resp->u.wifi_band =
|
||||
rpc_msg->resp_wifi_get_band->band;
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiSetBandMode: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_set_country_code);
|
||||
RPC_ERR_IN_RESP(resp_wifi_set_country_code);
|
||||
break;
|
||||
} case RPC_ID__Resp_WifiGetBandMode: {
|
||||
RPC_FAIL_ON_NULL(resp_wifi_get_bandmode);
|
||||
RPC_ERR_IN_RESP(resp_wifi_get_bandmode);
|
||||
app_resp->u.wifi_band_mode =
|
||||
rpc_msg->resp_wifi_get_bandmode->bandmode;
|
||||
break;
|
||||
#endif
|
||||
} default: {
|
||||
ESP_LOGE(TAG, "Unsupported rpc Resp[%u]", rpc_msg->msg_id);
|
||||
goto fail_parse_rpc_msg;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app_resp->resp_event_status = SUCCESS;
|
||||
return SUCCESS;
|
||||
|
||||
/* 5. Free up buffers in failure cases */
|
||||
fail_parse_rpc_msg:
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Espressif Systems Wireless LAN device driver
|
||||
*
|
||||
* Copyright (C) 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
#include "rpc_slave_if.h"
|
||||
#include "rpc_core.h"
|
||||
#include "esp_hosted_wifi_config.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
DEFINE_LOG_TAG(rpc_api);
|
||||
|
||||
#define RPC_SEND_REQ(msGiD) do { \
|
||||
assert(req); \
|
||||
req->msg_id = msGiD; \
|
||||
if(SUCCESS != rpc_send_req(req)) { \
|
||||
ESP_LOGE(TAG,"Failed to send control req 0x%x\n", req->msg_id); \
|
||||
return NULL; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define RPC_DECODE_RSP_IF_NOT_ASYNC() do { \
|
||||
if (req->rpc_rsp_cb) \
|
||||
return NULL; \
|
||||
return rpc_wait_and_parse_sync_resp(req); \
|
||||
} while(0);
|
||||
|
||||
|
||||
int rpc_slaveif_init(void)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s", __func__);
|
||||
return rpc_core_init();
|
||||
}
|
||||
|
||||
int rpc_slaveif_deinit(void)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s", __func__);
|
||||
return rpc_core_deinit();
|
||||
}
|
||||
|
||||
/** Control Req->Resp APIs **/
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_mac(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_GetMACAddress);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_mac(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_SetMacAddress);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_mode(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_GetWifiMode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_mode(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_SetWifiMode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_ps(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetPs);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_ps(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetPs);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_max_tx_power(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetMaxTxPower);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_max_tx_power(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetMaxTxPower);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_config_heartbeat(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_ConfigHeartbeat);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_ota_begin(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_OTABegin);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_ota_write(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_OTAWrite);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_ota_end(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_OTAEnd);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_init(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiInit);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_deinit(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiDeinit);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_start(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStart);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_stop(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStop);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_connect(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiConnect);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_disconnect(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiDisconnect);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_config(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetConfig);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_config(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetConfig);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_start(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiScanStart);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_stop(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiScanStop);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_num(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiScanGetApNum);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_record(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiScanGetApRecord);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_records(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiScanGetApRecords);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_clear_ap_list(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiClearApList);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_restore(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiRestore);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_clear_fast_connect(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiClearFastConnect);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_deauth_sta(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiDeauthSta);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_ap_info(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStaGetApInfo);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_storage(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetStorage);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_bandwidth(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetBandwidth);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_bandwidth(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetBandwidth);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_channel(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetChannel);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_channel(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetChannel);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_country_code(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetCountryCode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_country_code(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetCountryCode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_country(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetCountry);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_country(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetCountry);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_ap_get_sta_list(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiApGetStaList);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_ap_get_sta_aid(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiApGetStaAid);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_rssi(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStaGetRssi);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_protocol(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetProtocol);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_protocol(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetProtocol);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_negotiated_phymode(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStaGetNegotiatedPhymode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_aid(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiStaGetAid);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_protocols(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetProtocols);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_get_coprocessor_fwversion(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_GetCoprocessorFwVersion);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
#if H_WIFI_DUALBAND_SUPPORT
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_protocols(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetProtocols);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_bandwidths(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetBandwidths);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_bandwidths(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetBandwidths);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_band(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetBand);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_band(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetBand);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_band_mode(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiSetBandMode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_band_mode(ctrl_cmd_t *req)
|
||||
{
|
||||
RPC_SEND_REQ(RPC_ID__Req_WifiGetBandMode);
|
||||
RPC_DECODE_RSP_IF_NOT_ASYNC();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Espressif Systems Wireless LAN device driver
|
||||
*
|
||||
* Copyright (C) 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __RPC_SLAVE_IF_H
|
||||
#define __RPC_SLAVE_IF_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_hosted_rpc.pb-c.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "esp_hosted_wifi_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SSID_LENGTH 32
|
||||
#define BSSID_BYTES_SIZE 6
|
||||
#define PASSWORD_LENGTH 64
|
||||
#define STATUS_LENGTH 14
|
||||
#define VENDOR_OUI_BUF 3
|
||||
|
||||
/*
|
||||
#define SUCCESS 0
|
||||
#define FAILURE -1
|
||||
*/
|
||||
|
||||
#define CALLBACK_SET_SUCCESS 0
|
||||
#define CALLBACK_AVAILABLE 0
|
||||
#define CALLBACK_NOT_REGISTERED -1
|
||||
#define MSG_ID_OUT_OF_ORDER -2
|
||||
|
||||
#define MAX_FREE_BUFF_HANDLES 20
|
||||
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
|
||||
/* If request is already being served and
|
||||
* another request is pending, time period for
|
||||
* which new request will wait in seconds
|
||||
* */
|
||||
//#define WAIT_TIME_B2B_RPC_REQ 5
|
||||
#define DEFAULT_RPC_RSP_TIMEOUT 5
|
||||
#define DEFAULT_RPC_RSP_SCAN_TIMEOUT 30
|
||||
|
||||
#define SUCCESS_STR "success"
|
||||
#define FAILURE_STR "failure"
|
||||
#define NOT_CONNECTED_STR "not_connected"
|
||||
|
||||
#define RPC_RX_QUEUE_SIZE 3
|
||||
#define RPC_TX_QUEUE_SIZE 5
|
||||
|
||||
/*---- Control structures ----*/
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
uint8_t mac[BSSID_BYTES_SIZE];
|
||||
} wifi_mac_t;
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
} hosted_mode_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface;
|
||||
wifi_config_t u;
|
||||
} wifi_cfg_t;
|
||||
|
||||
|
||||
/** @brief Parameters for an SSID scan. */
|
||||
typedef struct {
|
||||
bool block;
|
||||
wifi_scan_config_t cfg;
|
||||
uint8_t cfg_set;
|
||||
} wifi_scan_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
//int count;
|
||||
int number;
|
||||
/* dynamic size */
|
||||
//wifi_scanlist_t *out_list;
|
||||
wifi_ap_record_t *out_list;
|
||||
} wifi_scan_ap_list_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t aid;
|
||||
} wifi_deauth_sta_t;
|
||||
|
||||
typedef struct {
|
||||
int ps_mode;
|
||||
} wifi_power_save_t;
|
||||
|
||||
typedef struct {
|
||||
bool enable;
|
||||
wifi_vendor_ie_type_t type;
|
||||
wifi_vendor_ie_id_t idx;
|
||||
vendor_ie_data_t vnd_ie;
|
||||
} wifi_softap_vendor_ie_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *ota_data;
|
||||
uint32_t ota_data_len;
|
||||
} ota_write_t;
|
||||
|
||||
typedef struct {
|
||||
int power;
|
||||
} wifi_tx_power_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_interface_t ifx;
|
||||
wifi_bandwidth_t bw;
|
||||
} rpc_wifi_bandwidth_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t primary;
|
||||
wifi_second_chan_t second;
|
||||
} rpc_wifi_channel_t;
|
||||
|
||||
typedef struct {
|
||||
char cc[3];
|
||||
bool ieee80211d_enabled;
|
||||
} rpc_wifi_country_code;
|
||||
|
||||
typedef struct {
|
||||
wifi_interface_t ifx;
|
||||
uint8_t protocol_bitmap;
|
||||
} rpc_wifi_protocol;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6];
|
||||
uint16_t aid;
|
||||
} rpc_wifi_ap_get_sta_aid_t;
|
||||
|
||||
typedef struct {
|
||||
int rssi;
|
||||
} rpc_wifi_sta_get_rssi_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_phy_mode_t phymode;
|
||||
} rpc_wifi_sta_get_negotiated_phymode_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t aid;
|
||||
} rpc_wifi_sta_get_aid_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_interface_t ifx;
|
||||
uint16_t ghz_2g;
|
||||
uint16_t ghz_5g;
|
||||
} rpc_wifi_protocols_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t major1;
|
||||
uint32_t minor1;
|
||||
uint32_t patch1;
|
||||
} rpc_coprocessor_fwversion_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_interface_t ifx;
|
||||
wifi_bandwidth_t ghz_2g;
|
||||
wifi_bandwidth_t ghz_5g;
|
||||
} rpc_wifi_bandwidths_t;
|
||||
|
||||
typedef struct {
|
||||
/* event */
|
||||
uint32_t hb_num;
|
||||
/* Req */
|
||||
uint8_t enable;
|
||||
uint32_t duration;
|
||||
} event_heartbeat_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t wifi_event_id;
|
||||
} event_wifi_simple_t;
|
||||
|
||||
typedef struct Ctrl_cmd_t {
|
||||
/* msg type could be 1. req 2. resp 3. notification */
|
||||
uint8_t msg_type;
|
||||
|
||||
/* control path protobuf msg number */
|
||||
uint16_t msg_id;
|
||||
|
||||
/* uid of request / response */
|
||||
uint32_t uid;
|
||||
|
||||
/* statusof response or notification */
|
||||
int32_t resp_event_status;
|
||||
|
||||
void * rx_sem;
|
||||
|
||||
union {
|
||||
wifi_init_config_t wifi_init_config;
|
||||
wifi_cfg_t wifi_config;
|
||||
wifi_mac_t wifi_mac;
|
||||
hosted_mode_t wifi_mode;
|
||||
|
||||
wifi_softap_vendor_ie_t wifi_softap_vendor_ie;
|
||||
//wifi_softap_conn_sta_list_t wifi_softap_con_sta;
|
||||
|
||||
wifi_power_save_t wifi_ps;
|
||||
|
||||
ota_write_t ota_write;
|
||||
|
||||
wifi_tx_power_t wifi_tx_power;
|
||||
|
||||
wifi_scan_cfg_t wifi_scan_config;
|
||||
|
||||
wifi_ap_record_t wifi_ap_record;
|
||||
|
||||
wifi_scan_ap_list_t wifi_scan_ap_list;
|
||||
|
||||
wifi_deauth_sta_t wifi_deauth_sta;
|
||||
|
||||
wifi_storage_t wifi_storage;
|
||||
|
||||
rpc_wifi_bandwidth_t wifi_bandwidth;
|
||||
|
||||
rpc_wifi_channel_t wifi_channel;
|
||||
|
||||
rpc_wifi_country_code wifi_country_code;
|
||||
|
||||
wifi_country_t wifi_country;
|
||||
|
||||
wifi_sta_list_t wifi_ap_sta_list;
|
||||
|
||||
rpc_wifi_ap_get_sta_aid_t wifi_ap_get_sta_aid;
|
||||
|
||||
rpc_wifi_sta_get_rssi_t wifi_sta_get_rssi;
|
||||
|
||||
rpc_wifi_protocol wifi_protocol;
|
||||
|
||||
rpc_wifi_sta_get_negotiated_phymode_t wifi_sta_get_negotiated_phymode;
|
||||
rpc_wifi_sta_get_aid_t wifi_sta_get_aid;
|
||||
|
||||
rpc_coprocessor_fwversion_t coprocessor_fwversion;
|
||||
|
||||
#if H_WIFI_DUALBAND_SUPPORT
|
||||
rpc_wifi_protocols_t wifi_protocols;
|
||||
|
||||
rpc_wifi_bandwidths_t wifi_bandwidths;
|
||||
|
||||
wifi_band_t wifi_band;
|
||||
|
||||
wifi_band_mode_t wifi_band_mode;
|
||||
#endif
|
||||
|
||||
event_heartbeat_t e_heartbeat;
|
||||
|
||||
event_wifi_simple_t e_wifi_simple;
|
||||
|
||||
wifi_event_ap_staconnected_t e_wifi_ap_staconnected;
|
||||
|
||||
wifi_event_ap_stadisconnected_t e_wifi_ap_stadisconnected;
|
||||
|
||||
wifi_event_sta_scan_done_t e_wifi_sta_scan_done;
|
||||
|
||||
wifi_event_sta_connected_t e_wifi_sta_connected;
|
||||
|
||||
wifi_event_sta_disconnected_t e_wifi_sta_disconnected;
|
||||
}u;
|
||||
|
||||
/* By default this callback is set to NULL.
|
||||
* When this callback is set by app while triggering request,
|
||||
* it will be automatically called asynchronously
|
||||
* by hosted control lib on receiving control response
|
||||
* in this case app will not be waiting for response.
|
||||
*
|
||||
* Whereas, when this is not set i.e. is NULL, it is understood
|
||||
* as synchronous response, and app after sending request,
|
||||
* will wait till getting a response
|
||||
*/
|
||||
int (*rpc_rsp_cb)(struct Ctrl_cmd_t *data);
|
||||
|
||||
/* Wait for timeout duration, if response not received,
|
||||
* it will send timeout response.
|
||||
* Default value for this time out is DEFAULT_RPC_RESP_TIMEOUT */
|
||||
int rsp_timeout_sec;
|
||||
|
||||
/* rpc takes only one request at a time.
|
||||
* If new request comes before previous command execution,
|
||||
* wait for previous command execution for these many seconds, else return failure.
|
||||
* Default: WAIT_TIME_B2B_RPC_REQ */
|
||||
int wait_prev_cmd_completion;
|
||||
|
||||
/* assign the data pointer to free by lower layer.
|
||||
* Ignored if assigned as NULL */
|
||||
void *app_free_buff_hdl;
|
||||
|
||||
/* free handle to be registered
|
||||
* Ignored if assigned as NULL */
|
||||
void (*app_free_buff_func)(void *app_free_buff_hdl);
|
||||
|
||||
void *rpc_free_buff_hdls[MAX_FREE_BUFF_HANDLES];
|
||||
uint8_t n_rpc_free_buff_hdls;
|
||||
} ctrl_cmd_t;
|
||||
|
||||
|
||||
/* resp callback */
|
||||
typedef int (*rpc_rsp_cb_t) (ctrl_cmd_t * resp);
|
||||
|
||||
/* event callback */
|
||||
typedef int (*rpc_evt_cb_t) (ctrl_cmd_t * event);
|
||||
|
||||
|
||||
/*---- Control API Function ----*/
|
||||
|
||||
|
||||
/* This file contains hosted control library exposed APIs.
|
||||
* For detailed documentation, Please refer `../../../docs/common/ctrl_apis.md`
|
||||
*
|
||||
* As important note, application using these APIs, should clean
|
||||
* 1. allocated buffer within library are saved in `app_resp->app_free_buff_hdl`
|
||||
* Please use `app_resp->app_free_buff_func` for freeing them.
|
||||
* 2. Response `ctrl_cmd_t *app_resp` is also allocated from library,
|
||||
* need to free using g_h.funcs->_h_free() function.
|
||||
**/
|
||||
|
||||
/* Set control event callback
|
||||
*
|
||||
* when user sets event callback, user provided function pointer
|
||||
* will be registered with user function
|
||||
* If user does not register event callback,
|
||||
* events received from ESP32 will be dropped
|
||||
*
|
||||
* Inputs:
|
||||
* > event - Control Event ID
|
||||
* > event_cb - NULL - resets event callback
|
||||
* Function pointer - Registers event callback
|
||||
* Returns:
|
||||
* > MSG_ID_OUT_OF_ORDER - If event is not registered with hosted control lib
|
||||
* > CALLBACK_SET_SUCCESS - Callback is set successful
|
||||
**/
|
||||
int set_event_callback(int event, rpc_rsp_cb_t event_cb);
|
||||
|
||||
/* Reset control event callback
|
||||
*
|
||||
* when user sets event callback, user provided function pointer
|
||||
* will be registered with user function
|
||||
* If user does not register event callback,
|
||||
* events received from ESP32 will be dropped
|
||||
*
|
||||
* Inputs:
|
||||
* > event - Control Event ID
|
||||
*
|
||||
* Returns:
|
||||
* > MSG_ID_OUT_OF_ORDER - If event is not registered with hosted control lib
|
||||
* > CALLBACK_SET_SUCCESS - Callback is set successful
|
||||
**/
|
||||
int reset_event_callback(int event);
|
||||
|
||||
|
||||
/* Initialize hosted control library
|
||||
*
|
||||
* This is first step for application while using control path
|
||||
* This will allocate and instantiate hosted control library
|
||||
*
|
||||
* Returns:
|
||||
* > SUCCESS - 0
|
||||
* > FAILURE - -1
|
||||
**/
|
||||
int rpc_slaveif_init(void);
|
||||
|
||||
/* De-initialize hosted control library
|
||||
*
|
||||
* This is last step for application while using control path
|
||||
* This will deallocate and cleanup hosted control library
|
||||
*
|
||||
* Returns:
|
||||
* > SUCCESS - 0
|
||||
* > FAILURE - -1
|
||||
**/
|
||||
int rpc_slaveif_deinit(void);
|
||||
|
||||
/* Get the MAC address of station or softAP interface of ESP32 */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_mac(ctrl_cmd_t *req);
|
||||
|
||||
/* Set MAC address of ESP32 interface for given wifi mode */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_mac(ctrl_cmd_t *req);
|
||||
|
||||
/* Get Wi-Fi mode of ESP32 */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_mode(ctrl_cmd_t *req);
|
||||
|
||||
/* Set the Wi-Fi mode of ESP32 */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_mode(ctrl_cmd_t *req);
|
||||
|
||||
/* Sets maximum WiFi transmitting power at ESP32 */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_max_tx_power(ctrl_cmd_t *req);
|
||||
|
||||
/* Gets maximum WiFi transmiting power at ESP32 */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_max_tx_power(ctrl_cmd_t *req);
|
||||
|
||||
/* Configure heartbeat event. Be default heartbeat is not enabled.
|
||||
* To enable heartbeats, user need to use this API in addition
|
||||
* to setting event callback for heartbeat event */
|
||||
ctrl_cmd_t * rpc_slaveif_config_heartbeat(ctrl_cmd_t *req);
|
||||
|
||||
/* Performs an OTA begin operation for ESP32 which erases and
|
||||
* prepares existing flash partition for new flash writing */
|
||||
ctrl_cmd_t * rpc_slaveif_ota_begin(ctrl_cmd_t *req);
|
||||
|
||||
/* Performs an OTA write operation for ESP32, It writes bytes from `ota_data`
|
||||
* buffer with `ota_data_len` number of bytes to OTA partition in flash. Number
|
||||
* of bytes can be small than size of complete binary to be flashed. In that
|
||||
* case, this caller is expected to repeatedly call this function till
|
||||
* total size written equals size of complete binary */
|
||||
ctrl_cmd_t * rpc_slaveif_ota_write(ctrl_cmd_t *req);
|
||||
|
||||
/* Performs an OTA end operation for ESP32, It validates written OTA image,
|
||||
* sets newly written OTA partition as boot partition for next boot,
|
||||
* Creates timer which reset ESP32 after 5 sec */
|
||||
ctrl_cmd_t * rpc_slaveif_ota_end(ctrl_cmd_t *req);
|
||||
|
||||
/* Gets the co-processor FW Version */
|
||||
ctrl_cmd_t * rpc_slaveif_get_coprocessor_fwversion(ctrl_cmd_t *req);
|
||||
|
||||
/* TODO: add descriptions */
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_init(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_deinit(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_start(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_stop(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_connect(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_disconnect(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_config(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_config(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_start(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_stop(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_num(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_record(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_scan_get_ap_records(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_clear_ap_list(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_restore(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_clear_fast_connect(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_deauth_sta(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_ap_info(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_ps(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_ps(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_storage(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_bandwidth(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_bandwidth(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_channel(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_channel(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_country_code(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_country_code(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_country(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_country(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_ap_get_sta_list(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_ap_get_sta_aid(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_rssi(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_protocol(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_protocol(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_negotiated_phymode(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_sta_get_aid(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_protocols(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_protocols(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_bandwidths(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_bandwidths(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_band(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_band(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_set_band_mode(ctrl_cmd_t *req);
|
||||
ctrl_cmd_t * rpc_slaveif_wifi_get_band_mode(ctrl_cmd_t *req);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1363
resources/espressif__esp_hosted/host/drivers/rpc/wrap/rpc_wrap.c
Normal file
1363
resources/espressif__esp_hosted/host/drivers/rpc/wrap/rpc_wrap.c
Normal file
File diff suppressed because it is too large
Load Diff
106
resources/espressif__esp_hosted/host/drivers/rpc/wrap/rpc_wrap.h
Normal file
106
resources/espressif__esp_hosted/host/drivers/rpc/wrap/rpc_wrap.h
Normal file
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __RPC_WRAP_H__
|
||||
#define __RPC_WRAP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Includes **/
|
||||
#include "common.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_hosted_wifi_config.h"
|
||||
#include "esp_hosted_api_types.h"
|
||||
#include "esp_hosted_ota.h"
|
||||
|
||||
/** Exported variables **/
|
||||
|
||||
/** Inline functions **/
|
||||
|
||||
/** Exported Functions **/
|
||||
esp_err_t rpc_init(void);
|
||||
esp_err_t rpc_deinit(void);
|
||||
esp_err_t rpc_unregister_event_callbacks(void);
|
||||
esp_err_t rpc_register_event_callbacks(void);
|
||||
|
||||
esp_err_t rpc_wifi_init(const wifi_init_config_t *arg);
|
||||
esp_err_t rpc_wifi_deinit(void);
|
||||
esp_err_t rpc_wifi_set_mode(wifi_mode_t mode);
|
||||
esp_err_t rpc_wifi_get_mode(wifi_mode_t* mode);
|
||||
esp_err_t rpc_wifi_start(void);
|
||||
esp_err_t rpc_wifi_stop(void);
|
||||
esp_err_t rpc_wifi_connect(void);
|
||||
esp_err_t rpc_wifi_disconnect(void);
|
||||
esp_err_t rpc_wifi_set_config(wifi_interface_t interface, wifi_config_t *conf);
|
||||
esp_err_t rpc_wifi_get_config(wifi_interface_t interface, wifi_config_t *conf);
|
||||
esp_err_t rpc_wifi_get_mac(wifi_interface_t mode, uint8_t mac[6]);
|
||||
esp_err_t rpc_wifi_set_mac(wifi_interface_t mode, const uint8_t mac[6]);
|
||||
|
||||
esp_err_t rpc_wifi_scan_start(const wifi_scan_config_t *config, bool block);
|
||||
esp_err_t rpc_wifi_scan_stop(void);
|
||||
esp_err_t rpc_wifi_scan_get_ap_num(uint16_t *number);
|
||||
esp_err_t rpc_wifi_scan_get_ap_record(wifi_ap_record_t *ap_record);
|
||||
esp_err_t rpc_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records);
|
||||
esp_err_t rpc_wifi_clear_ap_list(void);
|
||||
esp_err_t rpc_wifi_restore(void);
|
||||
esp_err_t rpc_wifi_clear_fast_connect(void);
|
||||
esp_err_t rpc_wifi_deauth_sta(uint16_t aid);
|
||||
esp_err_t rpc_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info);
|
||||
esp_err_t rpc_wifi_set_ps(wifi_ps_type_t type);
|
||||
esp_err_t rpc_wifi_get_ps(wifi_ps_type_t *type);
|
||||
esp_err_t rpc_wifi_set_storage(wifi_storage_t storage);
|
||||
esp_err_t rpc_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
||||
esp_err_t rpc_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
|
||||
esp_err_t rpc_wifi_set_channel(uint8_t primary, wifi_second_chan_t second);
|
||||
esp_err_t rpc_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
|
||||
esp_err_t rpc_wifi_set_country_code(const char *country, bool ieee80211d_enabled);
|
||||
esp_err_t rpc_wifi_get_country_code(char *country);
|
||||
esp_err_t rpc_wifi_set_country(const wifi_country_t *country);
|
||||
esp_err_t rpc_wifi_get_country(wifi_country_t *country);
|
||||
esp_err_t rpc_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
|
||||
esp_err_t rpc_wifi_ap_get_sta_aid(const uint8_t mac[6], uint16_t *aid);
|
||||
esp_err_t rpc_wifi_sta_get_rssi(int *rssi);
|
||||
esp_err_t rpc_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
|
||||
esp_err_t rpc_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
|
||||
esp_err_t rpc_wifi_set_max_tx_power(int8_t power);
|
||||
esp_err_t rpc_wifi_get_max_tx_power(int8_t *power);
|
||||
esp_err_t rpc_wifi_sta_get_negotiated_phymode(wifi_phy_mode_t *phymode);
|
||||
esp_err_t rpc_wifi_sta_get_aid(uint16_t *aid);
|
||||
|
||||
esp_err_t rpc_get_coprocessor_fwversion(esp_hosted_coprocessor_fwver_t *ver_info);
|
||||
|
||||
esp_err_t rpc_ota_begin(void);
|
||||
esp_err_t rpc_ota_write(uint8_t* ota_data, uint32_t ota_data_len);
|
||||
esp_err_t rpc_ota_end(void);
|
||||
|
||||
#if H_WIFI_DUALBAND_SUPPORT
|
||||
esp_err_t rpc_wifi_set_band(wifi_band_t band);
|
||||
esp_err_t rpc_wifi_get_band(wifi_band_t *band);
|
||||
esp_err_t rpc_wifi_set_band_mode(wifi_band_mode_t band_mode);
|
||||
esp_err_t rpc_wifi_get_band_mode(wifi_band_mode_t *band_mode);
|
||||
esp_err_t rpc_wifi_set_protocols(wifi_interface_t ifx, wifi_protocols_t *protocols);
|
||||
esp_err_t rpc_wifi_get_protocols(wifi_interface_t ifx, wifi_protocols_t *protocols);
|
||||
esp_err_t rpc_wifi_set_bandwidths(wifi_interface_t ifx, wifi_bandwidths_t *bw);
|
||||
esp_err_t rpc_wifi_get_bandwidths(wifi_interface_t ifx, wifi_bandwidths_t *bw);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
251
resources/espressif__esp_hosted/host/drivers/serial/serial_drv.c
Normal file
251
resources/espressif__esp_hosted/host/drivers/serial/serial_drv.c
Normal file
@@ -0,0 +1,251 @@
|
||||
// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "serial_if.h"
|
||||
#include "serial_ll_if.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_log.h"
|
||||
|
||||
DEFINE_LOG_TAG(serial);
|
||||
|
||||
struct serial_drv_handle_t {
|
||||
int handle; /* dummy variable */
|
||||
};
|
||||
|
||||
static serial_ll_handle_t * serial_ll_if_g;
|
||||
static void * readSemaphore;
|
||||
|
||||
|
||||
static void rpc_rx_indication(void);
|
||||
|
||||
/* -------- Serial Drv ---------- */
|
||||
struct serial_drv_handle_t* serial_drv_open(const char *transport)
|
||||
{
|
||||
struct serial_drv_handle_t* serial_drv_handle = NULL;
|
||||
if (!transport) {
|
||||
ESP_LOGE(TAG, "Invalid parameter in open");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(serial_drv_handle) {
|
||||
ESP_LOGE(TAG, "return orig hndl\n");
|
||||
return serial_drv_handle;
|
||||
}
|
||||
|
||||
serial_drv_handle = (struct serial_drv_handle_t*) g_h.funcs->_h_calloc
|
||||
(1,sizeof(struct serial_drv_handle_t));
|
||||
if (!serial_drv_handle) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory \n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return serial_drv_handle;
|
||||
}
|
||||
|
||||
int serial_drv_write (struct serial_drv_handle_t* serial_drv_handle,
|
||||
uint8_t* buf, int in_count, int* out_count)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!serial_drv_handle || !buf || !in_count || !out_count) {
|
||||
ESP_LOGE(TAG,"Invalid parameters in write\n\r");
|
||||
return RET_INVALID;
|
||||
}
|
||||
|
||||
if( (!serial_ll_if_g) ||
|
||||
(!serial_ll_if_g->fops) ||
|
||||
(!serial_ll_if_g->fops->write)) {
|
||||
ESP_LOGE(TAG,"serial interface not valid\n\r");
|
||||
return RET_INVALID;
|
||||
}
|
||||
|
||||
ESP_HEXLOGV("serial_write", buf, in_count);
|
||||
ret = serial_ll_if_g->fops->write(serial_ll_if_g, buf, in_count);
|
||||
if (ret != RET_OK) {
|
||||
*out_count = 0;
|
||||
ESP_LOGE(TAG,"Failed to write data\n\r");
|
||||
return RET_FAIL;
|
||||
}
|
||||
|
||||
*out_count = in_count;
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
uint8_t * serial_drv_read(struct serial_drv_handle_t *serial_drv_handle,
|
||||
uint32_t *out_nbyte)
|
||||
{
|
||||
uint16_t init_read_len = 0;
|
||||
uint16_t rx_buf_len = 0;
|
||||
uint8_t* read_buf = NULL;
|
||||
int ret = 0;
|
||||
/* Any of `RPC_EP_NAME_EVT` and `RPC_EP_NAME_RSP` could be used,
|
||||
* as both have same strlen in esp_hosted_transport.h */
|
||||
const char* ep_name = RPC_EP_NAME_RSP;
|
||||
uint8_t *buf = NULL;
|
||||
uint32_t buf_len = 0;
|
||||
|
||||
|
||||
if (!serial_drv_handle || !out_nbyte) {
|
||||
ESP_LOGE(TAG,"Invalid parameters in read\n\r");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_nbyte = 0;
|
||||
|
||||
if(!readSemaphore) {
|
||||
ESP_LOGE(TAG,"Semaphore not initialized\n\r");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_h.funcs->_h_get_semaphore(readSemaphore, HOSTED_BLOCK_MAX);
|
||||
|
||||
if( (!serial_ll_if_g) ||
|
||||
(!serial_ll_if_g->fops) ||
|
||||
(!serial_ll_if_g->fops->read)) {
|
||||
ESP_LOGE(TAG,"serial interface refusing to read\n\r");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get buffer from serial interface */
|
||||
read_buf = serial_ll_if_g->fops->read(serial_ll_if_g, &rx_buf_len);
|
||||
if ((!read_buf) || (!rx_buf_len)) {
|
||||
ESP_LOGE(TAG,"serial read failed\n\r");
|
||||
return NULL;
|
||||
}
|
||||
ESP_HEXLOGV("serial_read", read_buf, rx_buf_len);
|
||||
|
||||
/*
|
||||
* Read Operation happens in two steps because total read length is unknown
|
||||
* at first read.
|
||||
* 1) Read fixed length of RX data
|
||||
* 2) Read variable length of RX data
|
||||
*
|
||||
* (1) Read fixed length of RX data :
|
||||
* Read fixed length of received data in below format:
|
||||
* ----------------------------------------------------------------------------
|
||||
* Endpoint Type | Endpoint Length | Endpoint Value | Data Type | Data Length
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Bytes used per field as follows:
|
||||
* ---------------------------------------------------------------------------
|
||||
* 1 | 2 | Endpoint Length | 1 | 2 |
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* int_read_len = 1 + 2 + Endpoint length + 1 + 2
|
||||
*/
|
||||
|
||||
init_read_len = SIZE_OF_TYPE + SIZE_OF_LENGTH + strlen(ep_name) +
|
||||
SIZE_OF_TYPE + SIZE_OF_LENGTH;
|
||||
|
||||
if(rx_buf_len < init_read_len) {
|
||||
HOSTED_FREE(read_buf);
|
||||
ESP_LOGE(TAG,"Incomplete serial buff, return\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HOSTED_CALLOC(uint8_t,buf,init_read_len,free_bufs);
|
||||
|
||||
g_h.funcs->_h_memcpy(buf, read_buf, init_read_len);
|
||||
|
||||
/* parse_tlv function returns variable payload length
|
||||
* of received data in buf_len
|
||||
**/
|
||||
ret = parse_tlv(buf, &buf_len);
|
||||
if (ret || !buf_len) {
|
||||
HOSTED_FREE(buf);
|
||||
ESP_LOGE(TAG,"Failed to parse RX data \n\r");
|
||||
goto free_bufs;
|
||||
}
|
||||
|
||||
if (rx_buf_len < (init_read_len + buf_len)) {
|
||||
ESP_LOGE(TAG,"Buf read on serial iface is smaller than expected len\n");
|
||||
HOSTED_FREE(buf);
|
||||
goto free_bufs;
|
||||
}
|
||||
|
||||
if (rx_buf_len > (init_read_len + buf_len)) {
|
||||
ESP_LOGE(TAG,"Buf read on serial iface is smaller than expected len\n");
|
||||
}
|
||||
|
||||
HOSTED_FREE(buf);
|
||||
/*
|
||||
* (2) Read variable length of RX data:
|
||||
*/
|
||||
HOSTED_CALLOC(uint8_t,buf,buf_len,free_bufs);
|
||||
|
||||
g_h.funcs->_h_memcpy((buf), read_buf+init_read_len, buf_len);
|
||||
|
||||
HOSTED_FREE(read_buf);
|
||||
|
||||
*out_nbyte = buf_len;
|
||||
return buf;
|
||||
|
||||
free_bufs:
|
||||
HOSTED_FREE(read_buf);
|
||||
HOSTED_FREE(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int serial_drv_close(struct serial_drv_handle_t** serial_drv_handle)
|
||||
{
|
||||
if (!serial_drv_handle || !(*serial_drv_handle)) {
|
||||
ESP_LOGE(TAG,"Invalid parameter in close \n\r");
|
||||
if (serial_drv_handle)
|
||||
HOSTED_FREE(serial_drv_handle);
|
||||
return RET_INVALID;
|
||||
}
|
||||
HOSTED_FREE(*serial_drv_handle);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int rpc_platform_init(void)
|
||||
{
|
||||
/* rpc semaphore */
|
||||
readSemaphore = g_h.funcs->_h_create_semaphore(H_MAX_SYNC_RPC_REQUESTS +
|
||||
H_MAX_ASYNC_RPC_REQUESTS);
|
||||
assert(readSemaphore);
|
||||
|
||||
/* grab the semaphore, so that task will be mandated to wait on semaphore */
|
||||
g_h.funcs->_h_get_semaphore(readSemaphore, 0);
|
||||
|
||||
serial_ll_if_g = serial_ll_init(rpc_rx_indication);
|
||||
if (!serial_ll_if_g) {
|
||||
ESP_LOGE(TAG,"Serial interface creation failed\n\r");
|
||||
assert(serial_ll_if_g);
|
||||
return RET_FAIL;
|
||||
}
|
||||
if (RET_OK != serial_ll_if_g->fops->open(serial_ll_if_g)) {
|
||||
ESP_LOGE(TAG,"Serial interface open failed\n\r");
|
||||
return RET_FAIL;
|
||||
}
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/* TODO: Why this is not called in transport_pserial_close() */
|
||||
int rpc_platform_deinit(void)
|
||||
{
|
||||
if (RET_OK != serial_ll_if_g->fops->close(serial_ll_if_g)) {
|
||||
ESP_LOGE(TAG,"Serial interface close failed\n\r");
|
||||
return RET_FAIL;
|
||||
}
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static void rpc_rx_indication(void)
|
||||
{
|
||||
/* heads up to rpc for read */
|
||||
if(readSemaphore) {
|
||||
g_h.funcs->_h_post_semaphore(readSemaphore);
|
||||
}
|
||||
}
|
||||
107
resources/espressif__esp_hosted/host/drivers/serial/serial_drv.h
Normal file
107
resources/espressif__esp_hosted/host/drivers/serial/serial_drv.h
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/*prevent recursive inclusion */
|
||||
#ifndef __SERIAL_DRV_H
|
||||
#define __SERIAL_DRV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** includes **/
|
||||
#include "serial_ll_if.h"
|
||||
|
||||
/** Exported Functions **/
|
||||
/*
|
||||
* rpc_platform_init function initializes the rpc
|
||||
* path data structures
|
||||
* Input parameter
|
||||
* None
|
||||
* Returns
|
||||
* SUCCESS(0) or FAILURE(-1) of above operation
|
||||
*/
|
||||
int rpc_platform_init(void);
|
||||
|
||||
/*
|
||||
* rpc_platform_deinit function cleans up the rpc
|
||||
* path library data structure
|
||||
* Input parameter
|
||||
* None
|
||||
* Returns
|
||||
* SUCCESS(0) or FAILURE(-1) of above operation
|
||||
*/
|
||||
int rpc_platform_deinit(void);
|
||||
|
||||
/*
|
||||
* serial_drv_open function opens driver interface.
|
||||
*
|
||||
* Input parameter
|
||||
* transport : Pointer to transport driver
|
||||
* Returns
|
||||
* serial_drv_handle : Driver Handle
|
||||
*/
|
||||
struct serial_drv_handle_t* serial_drv_open (const char* transport);
|
||||
|
||||
/*
|
||||
* serial_drv_write function writes in_count bytes
|
||||
* from buffer to driver interface
|
||||
*
|
||||
* Input parameter
|
||||
* serial_drv_handle : Driver Handler
|
||||
* buf : Data Buffer (Data written from buf to
|
||||
* driver interface)
|
||||
* in_count : Number of Bytes to be written
|
||||
* Output parameter
|
||||
* out_count : Number of Bytes written
|
||||
*
|
||||
* Returns
|
||||
* SUCCESS(0) or FAILURE(-1) of above operation
|
||||
*/
|
||||
int serial_drv_write (struct serial_drv_handle_t* serial_drv_handle,
|
||||
uint8_t* buf, int in_count, int* out_count);
|
||||
|
||||
/*
|
||||
* serial_drv_read function gets buffer from serial driver
|
||||
* after TLV parsing. output buffer is protobuf encoded
|
||||
*
|
||||
* Input parameter
|
||||
* serial_drv_handle : Driver Handle
|
||||
* Output parameter
|
||||
* out_nbyte : Size of TLV parsed buffer
|
||||
* Returns
|
||||
* buf : Protocol encoded data Buffer
|
||||
* caller will decode the protobuf
|
||||
*/
|
||||
|
||||
uint8_t * serial_drv_read(struct serial_drv_handle_t *serial_drv_handle,
|
||||
uint32_t *out_nbyte);
|
||||
|
||||
/*
|
||||
* serial_drv_close function closes driver interface.
|
||||
*
|
||||
* Input parameter
|
||||
* serial_drv_handle : Driver Handle
|
||||
* Returns
|
||||
* SUCCESS(0) or FAILURE(-1) of above operation
|
||||
*/
|
||||
|
||||
int serial_drv_close (struct serial_drv_handle_t** serial_drv_handle);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,358 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 "string.h"
|
||||
#include "serial_ll_if.h"
|
||||
#include "esp_log.h"
|
||||
#include "transport_drv.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_header.h"
|
||||
|
||||
DEFINE_LOG_TAG(serial_ll);
|
||||
|
||||
/** Macros / Constants **/
|
||||
#define MAX_SERIAL_INTF 2
|
||||
#define TO_SERIAL_INFT_QUEUE_SIZE 100
|
||||
|
||||
typedef enum {
|
||||
INIT,
|
||||
ACTIVE,
|
||||
DESTROY
|
||||
} serial_ll_state_e;
|
||||
|
||||
static struct rx_data {
|
||||
int len;
|
||||
uint8_t *data;
|
||||
} r;
|
||||
|
||||
/* data structures needed for serial driver */
|
||||
static queue_handle_t to_serial_ll_intf_queue[MAX_SERIAL_INTF];
|
||||
static serial_ll_handle_t * interface_handle_g[MAX_SERIAL_INTF] = {NULL};
|
||||
static uint8_t conn_num = 0;
|
||||
|
||||
/** Function Declarations **/
|
||||
static int serial_ll_open (serial_ll_handle_t *serial_ll_hdl);
|
||||
static uint8_t * serial_ll_read (const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint16_t * rlen);
|
||||
static int serial_ll_write (const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint8_t * wbuffer, const uint16_t wlen);
|
||||
static int serial_ll_close (serial_ll_handle_t * serial_ll_hdl);
|
||||
|
||||
|
||||
/* define serial interface */
|
||||
static struct serial_ll_operations serial_ll_fops = {
|
||||
.open = serial_ll_open,
|
||||
.read = serial_ll_read,
|
||||
.write = serial_ll_write,
|
||||
.close = serial_ll_close,
|
||||
};
|
||||
|
||||
/** function definition **/
|
||||
|
||||
/** Local Functions **/
|
||||
|
||||
/**
|
||||
* @brief Open new Serial interface
|
||||
* @param serial_ll_hdl - handle of serial interface
|
||||
* @retval 0 if success, -1 on failure
|
||||
*/
|
||||
static int serial_ll_open(serial_ll_handle_t *serial_ll_hdl)
|
||||
{
|
||||
if (! serial_ll_hdl) {
|
||||
ESP_LOGE(TAG, "serial invalid hdr");
|
||||
return STM_FAIL;
|
||||
}
|
||||
|
||||
if (serial_ll_hdl->queue) {
|
||||
/* clean up earlier queue */
|
||||
g_h.funcs->_h_destroy_queue(serial_ll_hdl->queue);
|
||||
}
|
||||
|
||||
/* Queue - serial rx */
|
||||
serial_ll_hdl->queue = g_h.funcs->_h_create_queue(TO_SERIAL_INFT_QUEUE_SIZE,
|
||||
sizeof(interface_buffer_handle_t));
|
||||
|
||||
if (! serial_ll_hdl->queue) {
|
||||
serial_ll_close(serial_ll_hdl);
|
||||
return STM_FAIL;
|
||||
}
|
||||
|
||||
serial_ll_hdl->state = ACTIVE;
|
||||
return STM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get serial handle for iface_num
|
||||
* @param iface_num - serial connection number
|
||||
* @retval serial_ll_hdl - output handle of serial interface
|
||||
*/
|
||||
static serial_ll_handle_t * get_serial_ll_handle(const uint8_t iface_num)
|
||||
{
|
||||
if ((iface_num < MAX_SERIAL_INTF) &&
|
||||
(interface_handle_g[iface_num]) &&
|
||||
(interface_handle_g[iface_num]->state == ACTIVE)) {
|
||||
|
||||
return interface_handle_g[iface_num];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close serial interface
|
||||
* @param serial_ll_hdl - handle
|
||||
* @retval rbuffer - ready buffer read on serial inerface
|
||||
*/
|
||||
static int serial_ll_close(serial_ll_handle_t * serial_ll_hdl)
|
||||
{
|
||||
serial_ll_hdl->state = DESTROY;
|
||||
|
||||
if (serial_ll_hdl->queue) {
|
||||
g_h.funcs->_h_destroy_queue(serial_ll_hdl->queue);
|
||||
serial_ll_hdl->queue = NULL;
|
||||
}
|
||||
|
||||
/* reset connection */
|
||||
if (conn_num > 0) {
|
||||
interface_handle_g[--conn_num] = NULL;
|
||||
}
|
||||
|
||||
if (serial_ll_hdl) {
|
||||
g_h.funcs->_h_free(serial_ll_hdl);
|
||||
serial_ll_hdl = NULL;
|
||||
}
|
||||
return STM_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serial interface read non blocking
|
||||
* @param serial_ll_hdl - handle
|
||||
* rlen - output param, number of bytes read
|
||||
* @retval rbuffer - ready buffer read on serial inerface
|
||||
*/
|
||||
static uint8_t * serial_ll_read(const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint16_t * rlen)
|
||||
{
|
||||
/* This is a non-blocking call */
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
|
||||
/* Initial value */
|
||||
*rlen = 0 ;
|
||||
|
||||
/* check if serial interface valid */
|
||||
if ((! serial_ll_hdl) || (serial_ll_hdl->state != ACTIVE)) {
|
||||
ESP_LOGE(TAG, "serial invalid interface");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is **blocking** receive.
|
||||
*
|
||||
* Although not needed in normal circumstances,
|
||||
* User can convert it to non blocking using below steps:
|
||||
*
|
||||
* To make it non blocking:
|
||||
* As an another design option, serial_rx_callback can also be
|
||||
* thought of incoming data indication, i.e. asynchronous rx
|
||||
* indication, which can be used by higher layer in seperate
|
||||
* dedicated rx task to receive and process rx data.
|
||||
*
|
||||
* In our example, first approach of blocking read is used.
|
||||
*/
|
||||
if (g_h.funcs->_h_dequeue_item(serial_ll_hdl->queue, &buf_handle, HOSTED_BLOCK_MAX)) {
|
||||
ESP_LOGE(TAG, "serial queue recv failed ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* proceed only if payload and length are sane */
|
||||
if (!buf_handle.payload || !buf_handle.payload_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*rlen = buf_handle.payload_len;
|
||||
|
||||
return buf_handle.payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serial interface write
|
||||
* @param serial_ll_hdl - handle
|
||||
* wlen - number of bytes to write
|
||||
* wbuffer - buffer to send
|
||||
* @retval STM_FAIL/STM_OK
|
||||
*/
|
||||
static int serial_ll_write(const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint8_t * wbuffer, const uint16_t wlen)
|
||||
{
|
||||
|
||||
if ((! serial_ll_hdl) || (serial_ll_hdl->state != ACTIVE)) {
|
||||
ESP_LOGE(TAG, "serial invalid interface for write");
|
||||
return STM_FAIL;
|
||||
}
|
||||
|
||||
return esp_hosted_tx(serial_ll_hdl->if_type,
|
||||
serial_ll_hdl->if_num, wbuffer, wlen, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serial rx handler is called by spi driver when there
|
||||
* is incoming data with interface type is Serial.
|
||||
* @param if_num - interface instance
|
||||
* rxbuff - buffer from spi driver
|
||||
* rx_len - size of rxbuff
|
||||
* seq_num - serial sequence number
|
||||
* flag_more_frags - Flags for fragmentation
|
||||
* @retval 0 on success, else failure
|
||||
*/
|
||||
stm_ret_t serial_ll_rx_handler(interface_buffer_handle_t * buf_handle)
|
||||
{
|
||||
|
||||
#define SERIAL_ALLOC_REALLOC_RDATA() \
|
||||
do { \
|
||||
if(!r.data) { \
|
||||
r.data = (uint8_t *)g_h.funcs->_h_malloc(buf_handle->payload_len); \
|
||||
} else { \
|
||||
r.data = (uint8_t *)g_h.funcs->_h_realloc(r.data, r.len + buf_handle->payload_len); \
|
||||
} \
|
||||
if (!r.data) { \
|
||||
ESP_LOGE(TAG, "Failed to allocate serial data"); \
|
||||
goto serial_buff_cleanup; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
serial_ll_handle_t * serial_ll_hdl = NULL;
|
||||
uint8_t *serial_buf = NULL;
|
||||
interface_buffer_handle_t new_buf_handle = {0};
|
||||
|
||||
/* Check valid handle and length */
|
||||
if (!buf_handle || !buf_handle->payload_len) {
|
||||
ESP_LOGE(TAG, "%s:%u Invalid parameters", __func__, __LINE__);
|
||||
goto serial_buff_cleanup;
|
||||
}
|
||||
|
||||
serial_ll_hdl = get_serial_ll_handle(buf_handle->if_num);
|
||||
|
||||
/* Is serial interface up */
|
||||
if ((! serial_ll_hdl) || (serial_ll_hdl->state != ACTIVE)) {
|
||||
ESP_LOGE(TAG, "Serial interface not registered yet");
|
||||
goto serial_buff_cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Accumulate fragments */
|
||||
if (buf_handle->flag & MORE_FRAGMENT) {
|
||||
|
||||
ESP_LOGD(TAG, "Fragment!!!");
|
||||
SERIAL_ALLOC_REALLOC_RDATA();
|
||||
|
||||
g_h.funcs->_h_memcpy((r.data + r.len), buf_handle->payload, buf_handle->payload_len);
|
||||
r.len += buf_handle->payload_len;
|
||||
return STM_OK;
|
||||
}
|
||||
|
||||
SERIAL_ALLOC_REALLOC_RDATA();
|
||||
|
||||
/* No or last fragment */
|
||||
g_h.funcs->_h_memcpy((r.data + r.len), buf_handle->payload, buf_handle->payload_len);
|
||||
r.len += buf_handle->payload_len;
|
||||
|
||||
serial_buf = (uint8_t *)g_h.funcs->_h_malloc(r.len);
|
||||
if(!serial_buf) {
|
||||
ESP_LOGE(TAG, "Malloc failed, drop pkt");
|
||||
goto serial_buff_cleanup;
|
||||
}
|
||||
g_h.funcs->_h_memcpy(serial_buf, r.data, r.len);
|
||||
|
||||
/* form new buf handle for processing of serial msg */
|
||||
new_buf_handle.if_type = ESP_SERIAL_IF;
|
||||
new_buf_handle.if_num = buf_handle->if_num;
|
||||
new_buf_handle.payload_len = r.len;
|
||||
new_buf_handle.payload = serial_buf;
|
||||
new_buf_handle.priv_buffer_handle = serial_buf;
|
||||
new_buf_handle.free_buf_handle = g_h.funcs->_h_free;
|
||||
|
||||
/* clear old buf handle */
|
||||
//H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle, buf_handle->priv_buffer_handle);
|
||||
|
||||
|
||||
r.len = 0;
|
||||
g_h.funcs->_h_free(r.data);
|
||||
r.data = NULL;
|
||||
|
||||
/* send to serial queue */
|
||||
if (g_h.funcs->_h_queue_item(serial_ll_hdl->queue,
|
||||
&new_buf_handle, HOSTED_BLOCK_MAX)) {
|
||||
ESP_LOGE(TAG, "Failed send serialif queue[%u]", new_buf_handle.if_num);
|
||||
goto serial_buff_cleanup;
|
||||
}
|
||||
|
||||
/* Indicate higher layer about data ready for consumption */
|
||||
if (serial_ll_hdl->serial_rx_callback) {
|
||||
(*serial_ll_hdl->serial_rx_callback) ();
|
||||
} else {
|
||||
goto serial_buff_cleanup;
|
||||
}
|
||||
|
||||
return STM_OK;
|
||||
|
||||
serial_buff_cleanup:
|
||||
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle, buf_handle->priv_buffer_handle);
|
||||
|
||||
r.len = 0;
|
||||
|
||||
H_FREE_PTR_WITH_FUNC(new_buf_handle.free_buf_handle, new_buf_handle.priv_buffer_handle);
|
||||
|
||||
g_h.funcs->_h_free(r.data);
|
||||
return STM_FAIL;
|
||||
}
|
||||
|
||||
/** Exported Functions **/
|
||||
|
||||
/**
|
||||
* @brief create and return new serial interface
|
||||
* @param serial_rx_callback - callback to be invoked on rx data
|
||||
* @retval serial_ll_hdl - output handle of serial interface
|
||||
*/
|
||||
serial_ll_handle_t * serial_ll_init(void(*serial_rx_callback)(void))
|
||||
{
|
||||
serial_ll_handle_t * serial_ll_hdl = NULL;
|
||||
|
||||
/* Check if more serial interfaces be created */
|
||||
if ((conn_num+1) < MAX_SERIAL_INTF) {
|
||||
|
||||
serial_ll_hdl = (serial_ll_handle_t *)g_h.funcs->_h_malloc(sizeof(serial_ll_handle_t));
|
||||
if (! serial_ll_hdl) {
|
||||
ESP_LOGE(TAG, "Serial interface - malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serial_ll_hdl->if_type = ESP_SERIAL_IF;
|
||||
serial_ll_hdl->if_num = conn_num;
|
||||
serial_ll_hdl->queue = to_serial_ll_intf_queue[conn_num];
|
||||
serial_ll_hdl->state = INIT;
|
||||
serial_ll_hdl->fops = &serial_ll_fops;
|
||||
serial_ll_hdl->serial_rx_callback = serial_rx_callback;
|
||||
interface_handle_g[conn_num] = serial_ll_hdl;
|
||||
conn_num++;
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Number of serial interface connections overflow");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return serial_ll_hdl;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/*prevent recursive inclusion */
|
||||
#ifndef __SERIAL_LL_IF_H
|
||||
#define __SERIAL_LL_IF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** includes **/
|
||||
#include "transport_drv.h"
|
||||
#include "os_wrapper.h"
|
||||
|
||||
struct serial_ll_operations;
|
||||
|
||||
/* serial interface handle */
|
||||
typedef struct serial_handle_s {
|
||||
queue_handle_t queue;
|
||||
uint8_t if_type;
|
||||
uint8_t if_num;
|
||||
struct serial_ll_operations *fops;
|
||||
uint8_t state;
|
||||
void (*serial_rx_callback) (void);
|
||||
} serial_ll_handle_t;
|
||||
|
||||
/* serial interface */
|
||||
struct serial_ll_operations {
|
||||
/**
|
||||
* @brief Open new Serial interface
|
||||
* @param serial_ll_hdl - handle of serial interface
|
||||
* @retval 0 if success, -1 on failure
|
||||
*/
|
||||
int (*open) (serial_ll_handle_t *serial_ll_hdl);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serial interface read non blocking
|
||||
* This is non blocking receive
|
||||
* In case higher layer using serial interface needs to make
|
||||
* blocking read, it should register serial_rx_callback through
|
||||
* serial_ll_init.
|
||||
*
|
||||
* serial_rx_callback is notification mechanism to implementer of
|
||||
* serial interface. Higher layer would understand there is data
|
||||
* is ready through this notification. Then higer layer should do
|
||||
* serial_read API to receive actual data.
|
||||
*
|
||||
* As an another design option, serial_rx_callback can also be
|
||||
* thought of incoming data indication, i.e. asynchronous rx
|
||||
* indication, which can be used by higher layer in seperate
|
||||
* dedicated rx task to receive and process rx data.
|
||||
*
|
||||
* @param serial_ll_hdl - handle
|
||||
* rlen - output param, number of bytes read
|
||||
*
|
||||
* @retval rbuffer - ready buffer read on serial inerface
|
||||
*/
|
||||
uint8_t * (*read) (const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint16_t * rlen);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serial interface write
|
||||
* @param serial_ll_hdl - handle
|
||||
* wlen - number of bytes to write
|
||||
* wbuffer - buffer to send
|
||||
* @retval STM_FAIL/STM_OK
|
||||
*/
|
||||
int (*write) (const serial_ll_handle_t * serial_ll_hdl,
|
||||
uint8_t * wbuffer, const uint16_t wlen);
|
||||
|
||||
|
||||
/**
|
||||
* @brief close - Close serial interface
|
||||
* @param serial_ll_hdl - handle
|
||||
* @retval rbuffer - ready buffer read on serial inerface
|
||||
*/
|
||||
int (*close) (serial_ll_handle_t * serial_ll_hdl);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief serial_ll_init - create and return new serial interface
|
||||
* @param serial_rx_callback - callback to be invoked on rx data
|
||||
* @retval serial_ll_hdl - output handle of serial interface
|
||||
*/
|
||||
serial_ll_handle_t * serial_ll_init(void(*rx_data_ind)(void));
|
||||
|
||||
stm_ret_t serial_ll_rx_handler(interface_buffer_handle_t * buf_handle);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SERIAL_LL_IF_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __SDIO_DRV_H
|
||||
#define __SDIO_DRV_H
|
||||
|
||||
/** Includes **/
|
||||
#include "common.h"
|
||||
|
||||
/** Constants/Macros **/
|
||||
|
||||
/** Exported Structures **/
|
||||
|
||||
/** Exported variables **/
|
||||
|
||||
/** Inline functions **/
|
||||
|
||||
/** Exported Functions **/
|
||||
|
||||
#endif /* __SDIO_DRV_H */
|
||||
@@ -0,0 +1,116 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Espressif Systems Wireless LAN device driver
|
||||
*
|
||||
* Copyright (C) 2015-2023 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* This software file (the "File") is distributed by Espressif Systems (Shanghai)
|
||||
* PTE LTD under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available by writing to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
||||
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_REG_H
|
||||
#define __SDIO_REG_H
|
||||
|
||||
/** Includes **/
|
||||
#include "common.h"
|
||||
|
||||
/** constants/macros **/
|
||||
#define SD_IO_CCCR_FN_ENABLE 0x02
|
||||
#define SD_IO_CCCR_FN_READY 0x03
|
||||
#define SD_IO_CCCR_INT_ENABLE 0x04
|
||||
#define SD_IO_CCCR_BUS_WIDTH 0x07
|
||||
|
||||
#define CCCR_BUS_WIDTH_ECSI (1<<5)
|
||||
|
||||
#define SD_IO_CCCR_BLKSIZEL 0x10
|
||||
#define SD_IO_CCCR_BLKSIZEH 0x11
|
||||
|
||||
/* Interrupt Status */
|
||||
#define ESP_SLAVE_BIT0_INT BIT(0)
|
||||
#define ESP_SLAVE_BIT1_INT BIT(1)
|
||||
#define ESP_SLAVE_BIT2_INT BIT(2)
|
||||
#define ESP_SLAVE_BIT3_INT BIT(3)
|
||||
#define ESP_SLAVE_BIT4_INT BIT(4)
|
||||
#define ESP_SLAVE_BIT5_INT BIT(5)
|
||||
#define ESP_SLAVE_BIT6_INT BIT(6)
|
||||
#define ESP_SLAVE_BIT7_INT BIT(7)
|
||||
#define ESP_SLAVE_RX_UNDERFLOW_INT BIT(16)
|
||||
#define ESP_SLAVE_TX_OVERFLOW_INT BIT(17)
|
||||
#define ESP_SLAVE_RX_NEW_PACKET_INT BIT(23)
|
||||
|
||||
#define ESP_SLAVE_CMD53_END_ADDR 0x1F800
|
||||
#define ESP_SLAVE_LEN_MASK 0xFFFFF
|
||||
#define ESP_BLOCK_SIZE 512
|
||||
#define ESP_RX_BYTE_MAX 0x100000
|
||||
#define ESP_RX_BUFFER_SIZE 1536
|
||||
|
||||
#define ESP_TX_BUFFER_MASK 0xFFF
|
||||
#define ESP_TX_BUFFER_MAX 0x1000
|
||||
#define ESP_MAX_BUF_CNT 10
|
||||
|
||||
#define ESP_SLAVE_SLCHOST_BASE 0x3FF55000
|
||||
|
||||
#define HOST_TO_SLAVE_INTR ESP_SLAVE_SCRATCH_REG_7
|
||||
/* SLAVE registers */
|
||||
/* Interrupt Registers */
|
||||
#define ESP_SLAVE_INT_RAW_REG (ESP_SLAVE_SLCHOST_BASE + 0x50)
|
||||
#define ESP_SLAVE_INT_ST_REG (ESP_SLAVE_SLCHOST_BASE + 0x58)
|
||||
#define ESP_SLAVE_INT_CLR_REG (ESP_SLAVE_SLCHOST_BASE + 0xD4)
|
||||
#define ESP_HOST_INT_ENA_REG (ESP_SLAVE_SLCHOST_BASE + 0xDC)
|
||||
|
||||
/* Host side interrupts for ESP_HOST_INT_ENA_REG */
|
||||
#if H_SLAVE_TARGET_ESP32 || H_SLAVE_TARGET_ESP32C6 || H_SLAVE_TARGET_ESP32C5
|
||||
#define SDIO_INT_NEW_PACKET (23)
|
||||
#define SDIO_INT_START_THROTTLE (7)
|
||||
#define SDIO_INT_STOP_THROTTLE (6)
|
||||
#else
|
||||
#error "SDIO New Packet Intr Bit not defined for Hosted Slave"
|
||||
#endif
|
||||
|
||||
/* Data path registers*/
|
||||
#define ESP_SLAVE_PACKET_LEN_REG (ESP_SLAVE_SLCHOST_BASE + 0x60)
|
||||
#define ESP_SLAVE_TOKEN_RDATA (ESP_SLAVE_SLCHOST_BASE + 0x44)
|
||||
|
||||
/* Scratch registers*/
|
||||
#define ESP_SLAVE_SCRATCH_REG_0 (ESP_SLAVE_SLCHOST_BASE + 0x6C)
|
||||
#define ESP_SLAVE_SCRATCH_REG_1 (ESP_SLAVE_SLCHOST_BASE + 0x70)
|
||||
#define ESP_SLAVE_SCRATCH_REG_2 (ESP_SLAVE_SLCHOST_BASE + 0x74)
|
||||
#define ESP_SLAVE_SCRATCH_REG_3 (ESP_SLAVE_SLCHOST_BASE + 0x78)
|
||||
#define ESP_SLAVE_SCRATCH_REG_4 (ESP_SLAVE_SLCHOST_BASE + 0x7C)
|
||||
#define ESP_SLAVE_SCRATCH_REG_6 (ESP_SLAVE_SLCHOST_BASE + 0x88)
|
||||
#define ESP_SLAVE_SCRATCH_REG_7 (ESP_SLAVE_SLCHOST_BASE + 0x8C)
|
||||
#define ESP_SLAVE_SCRATCH_REG_8 (ESP_SLAVE_SLCHOST_BASE + 0x9C)
|
||||
#define ESP_SLAVE_SCRATCH_REG_9 (ESP_SLAVE_SLCHOST_BASE + 0xA0)
|
||||
#define ESP_SLAVE_SCRATCH_REG_10 (ESP_SLAVE_SLCHOST_BASE + 0xA4)
|
||||
#define ESP_SLAVE_SCRATCH_REG_11 (ESP_SLAVE_SLCHOST_BASE + 0xA8)
|
||||
#define ESP_SLAVE_SCRATCH_REG_12 (ESP_SLAVE_SLCHOST_BASE + 0xAC)
|
||||
#define ESP_SLAVE_SCRATCH_REG_13 (ESP_SLAVE_SLCHOST_BASE + 0xB0)
|
||||
#define ESP_SLAVE_SCRATCH_REG_14 (ESP_SLAVE_SLCHOST_BASE + 0xB4)
|
||||
#define ESP_SLAVE_SCRATCH_REG_15 (ESP_SLAVE_SLCHOST_BASE + 0xB8)
|
||||
|
||||
#define ESP_ADDRESS_MASK (0x3FF)
|
||||
|
||||
#define ESP_VENDOR_ID (0x6666)
|
||||
#define ESP_DEVICE_ID_1 (0x2222)
|
||||
#define ESP_DEVICE_ID_2 (0x3333)
|
||||
|
||||
|
||||
#define SDIO_REG(x) ((x)&ESP_ADDRESS_MASK)
|
||||
|
||||
#define SDIO_FUNC_0 (0)
|
||||
#define SDIO_FUNC_1 (1)
|
||||
|
||||
#define ESP_SDIO_CONF_OFFSET (0)
|
||||
#define ESP_SDIO_SEND_OFFSET (16)
|
||||
|
||||
#endif /* __SDIO_REG_H */
|
||||
@@ -0,0 +1,713 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#include "mempool.h"
|
||||
#include "common.h"
|
||||
#include "esp_hosted_config.h"
|
||||
//#include "netdev_if.h"
|
||||
#include "transport_drv.h"
|
||||
#include "spi_drv.h"
|
||||
#include "serial_drv.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_log.h"
|
||||
#include "stats.h"
|
||||
#include "hci_drv.h"
|
||||
#include "endian.h"
|
||||
|
||||
DEFINE_LOG_TAG(spi);
|
||||
|
||||
void * spi_handle = NULL;
|
||||
semaphore_handle_t spi_trans_ready_sem;
|
||||
|
||||
#if DEBUG_HOST_TX_SEMAPHORE
|
||||
#define H_DEBUG_GPIO_PIN_Host_Tx_Port NULL
|
||||
#define H_DEBUG_GPIO_PIN_Host_Tx_Pin -1
|
||||
#endif
|
||||
|
||||
static uint8_t schedule_dummy_rx = 0;
|
||||
|
||||
static void * spi_transaction_thread;
|
||||
/* TODO to move this in transport drv */
|
||||
extern transport_channel_t *chan_arr[ESP_MAX_IF];
|
||||
|
||||
/* Create mempool for cache mallocs */
|
||||
static struct mempool * buf_mp_g;
|
||||
|
||||
/** Exported variables **/
|
||||
|
||||
static void * spi_bus_lock;
|
||||
|
||||
/* Queue declaration */
|
||||
static queue_handle_t to_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
semaphore_handle_t sem_to_slave_queue;
|
||||
static queue_handle_t from_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
semaphore_handle_t sem_from_slave_queue;
|
||||
|
||||
static void * spi_rx_thread;
|
||||
|
||||
|
||||
/** function declaration **/
|
||||
/** Exported functions **/
|
||||
static void spi_transaction_task(void const* pvParameters);
|
||||
static void spi_process_rx_task(void const* pvParameters);
|
||||
static uint8_t * get_next_tx_buffer(uint8_t *is_valid_tx_buf, void (**free_func)(void* ptr));
|
||||
|
||||
static inline void spi_mempool_create(void)
|
||||
{
|
||||
MEM_DUMP("spi_mempool_create");
|
||||
buf_mp_g = mempool_create(MAX_SPI_BUFFER_SIZE);
|
||||
#ifdef H_USE_MEMPOOL
|
||||
assert(buf_mp_g);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void spi_mempool_destroy(void)
|
||||
{
|
||||
mempool_destroy(buf_mp_g);
|
||||
}
|
||||
|
||||
static inline void *spi_buffer_alloc(uint32_t need_memset)
|
||||
{
|
||||
return mempool_alloc(buf_mp_g, MAX_SPI_BUFFER_SIZE, need_memset);
|
||||
}
|
||||
|
||||
static inline void spi_buffer_free(void *buf)
|
||||
{
|
||||
mempool_free(buf_mp_g, buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This ISR is called when the handshake or data_ready line goes high.
|
||||
*/
|
||||
static void FAST_RAM_ATTR gpio_hs_isr_handler(void* arg)
|
||||
{
|
||||
#if 0
|
||||
//Sometimes due to interference or ringing or something, we get two irqs after eachother. This is solved by
|
||||
//looking at the time between interrupts and refusing any interrupt too close to another one.
|
||||
static uint32_t lasthandshaketime_us;
|
||||
uint32_t currtime_us = esp_timer_get_time();
|
||||
uint32_t diff = currtime_us - lasthandshaketime_us;
|
||||
if (diff < 1000) {
|
||||
return; //ignore everything <1ms after an earlier irq
|
||||
}
|
||||
lasthandshaketime_us = currtime_us;
|
||||
#endif
|
||||
g_h.funcs->_h_post_semaphore_from_isr(spi_trans_ready_sem);
|
||||
ESP_EARLY_LOGV(TAG, "%s", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
This ISR is called when the handshake or data_ready line goes high.
|
||||
*/
|
||||
static void FAST_RAM_ATTR gpio_dr_isr_handler(void* arg)
|
||||
{
|
||||
g_h.funcs->_h_post_semaphore_from_isr(spi_trans_ready_sem);
|
||||
ESP_EARLY_LOGV(TAG, "%s", __func__);
|
||||
}
|
||||
|
||||
void transport_deinit_internal(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief transport initializes
|
||||
* @param transport_evt_handler_fp - event handler
|
||||
* @retval None
|
||||
*/
|
||||
void transport_init_internal(void)
|
||||
{
|
||||
uint8_t prio_q_idx;
|
||||
|
||||
spi_bus_lock = g_h.funcs->_h_create_mutex();
|
||||
assert(spi_bus_lock);
|
||||
|
||||
|
||||
sem_to_slave_queue = g_h.funcs->_h_create_semaphore(TO_SLAVE_QUEUE_SIZE*MAX_PRIORITY_QUEUES);
|
||||
assert(sem_to_slave_queue);
|
||||
sem_from_slave_queue = g_h.funcs->_h_create_semaphore(FROM_SLAVE_QUEUE_SIZE*MAX_PRIORITY_QUEUES);
|
||||
assert(sem_from_slave_queue);
|
||||
|
||||
for (prio_q_idx=0; prio_q_idx<MAX_PRIORITY_QUEUES;prio_q_idx++) {
|
||||
/* Queue - rx */
|
||||
from_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(FROM_SLAVE_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(from_slave_queue[prio_q_idx]);
|
||||
|
||||
/* Queue - tx */
|
||||
to_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(TO_SLAVE_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(to_slave_queue[prio_q_idx]);
|
||||
}
|
||||
|
||||
spi_mempool_create();
|
||||
|
||||
/* Creates & Give sem for next spi trans */
|
||||
spi_trans_ready_sem = g_h.funcs->_h_create_semaphore(1);
|
||||
assert(spi_trans_ready_sem);
|
||||
|
||||
spi_handle = g_h.funcs->_h_bus_init();
|
||||
if (!spi_handle) {
|
||||
ESP_LOGE(TAG, "could not create spi handle, exiting\n");
|
||||
assert(spi_handle);
|
||||
}
|
||||
|
||||
/* Task - SPI transaction (full duplex) */
|
||||
spi_transaction_thread = g_h.funcs->_h_thread_create("spi_trans", DFLT_TASK_PRIO,
|
||||
DFLT_TASK_STACK_SIZE, spi_transaction_task, NULL);
|
||||
assert(spi_transaction_thread);
|
||||
|
||||
/* Task - RX processing */
|
||||
spi_rx_thread = g_h.funcs->_h_thread_create("spi_rx", DFLT_TASK_PRIO,
|
||||
DFLT_TASK_STACK_SIZE, spi_process_rx_task, NULL);
|
||||
assert(spi_rx_thread);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Schedule SPI transaction if -
|
||||
* a. valid TX buffer is ready at SPI host (STM)
|
||||
* b. valid TX buffer is ready at SPI peripheral (ESP)
|
||||
* c. Dummy transaction is expected from SPI peripheral (ESP)
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
static int process_spi_rx_buf(uint8_t * rxbuff)
|
||||
{
|
||||
struct esp_payload_header *payload_header;
|
||||
uint16_t rx_checksum = 0, checksum = 0;
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
uint16_t len, offset;
|
||||
int ret = 0;
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
|
||||
if (!rxbuff)
|
||||
return -1;
|
||||
|
||||
ESP_HEXLOGV("h_spi_rx", rxbuff, 16);
|
||||
|
||||
/* create buffer rx handle, used for processing */
|
||||
payload_header = (struct esp_payload_header *) rxbuff;
|
||||
|
||||
/* Fetch length and offset from payload header */
|
||||
len = le16toh(payload_header->len);
|
||||
offset = le16toh(payload_header->offset);
|
||||
|
||||
if (ESP_MAX_IF == payload_header->if_type)
|
||||
schedule_dummy_rx = 0;
|
||||
|
||||
if (!len) {
|
||||
wifi_tx_throttling = payload_header->throttle_cmd;
|
||||
ret = -5;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((len > MAX_PAYLOAD_SIZE) ||
|
||||
(offset != sizeof(struct esp_payload_header))) {
|
||||
ESP_LOGI(TAG, "rx packet ignored: len [%u], rcvd_offset[%u], exp_offset[%u]\n",
|
||||
len, offset, sizeof(struct esp_payload_header));
|
||||
|
||||
/* 1. no payload to process
|
||||
* 2. input packet size > driver capacity
|
||||
* 3. payload header size mismatch,
|
||||
* wrong header/bit packing?
|
||||
* */
|
||||
ret = -2;
|
||||
goto done;
|
||||
|
||||
} else {
|
||||
rx_checksum = le16toh(payload_header->checksum);
|
||||
payload_header->checksum = 0;
|
||||
|
||||
checksum = compute_checksum(rxbuff, len+offset);
|
||||
//TODO: checksum needs to be configurable from menuconfig
|
||||
if (checksum == rx_checksum) {
|
||||
buf_handle.priv_buffer_handle = rxbuff;
|
||||
buf_handle.free_buf_handle = spi_buffer_free;
|
||||
buf_handle.payload_len = len;
|
||||
buf_handle.if_type = payload_header->if_type;
|
||||
buf_handle.if_num = payload_header->if_num;
|
||||
buf_handle.payload = rxbuff + offset;
|
||||
buf_handle.seq_num = le16toh(payload_header->seq_num);
|
||||
buf_handle.flag = payload_header->flags;
|
||||
wifi_tx_throttling = payload_header->throttle_cmd;
|
||||
#if 0
|
||||
#if CONFIG_H_LOWER_MEMCOPY
|
||||
if ((buf_handle.if_type == ESP_STA_IF) ||
|
||||
(buf_handle.if_type == ESP_AP_IF))
|
||||
buf_handle.payload_zcopy = 1;
|
||||
#endif
|
||||
#endif
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_in++;
|
||||
#endif
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
/* else OTHERS by default */
|
||||
|
||||
g_h.funcs->_h_queue_item(from_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_from_slave_queue);
|
||||
|
||||
} else {
|
||||
ESP_LOGI(TAG, "rcvd_crc[%u] != exp_crc[%u], drop pkt\n",checksum, rx_checksum);
|
||||
ret = -4;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
done:
|
||||
/* error cases, abort */
|
||||
if (rxbuff) {
|
||||
spi_buffer_free(rxbuff);
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.spi_mem_stats.rx_freed++;
|
||||
#endif
|
||||
rxbuff = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_and_execute_spi_transaction(void)
|
||||
{
|
||||
uint8_t *txbuff = NULL;
|
||||
uint8_t *rxbuff = NULL;
|
||||
uint8_t is_valid_tx_buf = 0;
|
||||
void (*tx_buff_free_func)(void* ptr) = NULL;
|
||||
struct esp_payload_header *h = NULL;
|
||||
static uint8_t schedule_dummy_tx = 0;
|
||||
|
||||
uint32_t ret = 0;
|
||||
struct hosted_transport_context_t spi_trans = {0};
|
||||
gpio_pin_state_t gpio_handshake = H_HS_VAL_INACTIVE;
|
||||
gpio_pin_state_t gpio_rx_data_ready = H_DR_VAL_INACTIVE;
|
||||
|
||||
g_h.funcs->_h_lock_mutex(spi_bus_lock, HOSTED_BLOCK_MAX);
|
||||
|
||||
/* handshake line SET -> slave ready for next transaction */
|
||||
gpio_handshake = g_h.funcs->_h_read_gpio(H_GPIO_HANDSHAKE_Port,
|
||||
H_GPIO_HANDSHAKE_Pin);
|
||||
|
||||
/* data ready line SET -> slave wants to send something */
|
||||
gpio_rx_data_ready = g_h.funcs->_h_read_gpio(H_GPIO_DATA_READY_Port,
|
||||
H_GPIO_DATA_READY_Pin);
|
||||
|
||||
if (gpio_handshake == H_HS_VAL_ACTIVE) {
|
||||
|
||||
/* Get next tx buffer to be sent */
|
||||
txbuff = get_next_tx_buffer(&is_valid_tx_buf, &tx_buff_free_func);
|
||||
|
||||
if ( (gpio_rx_data_ready == H_DR_VAL_ACTIVE) ||
|
||||
(is_valid_tx_buf) || schedule_dummy_tx || schedule_dummy_rx ) {
|
||||
|
||||
if (!txbuff) {
|
||||
/* Even though, there is nothing to send,
|
||||
* valid reseted txbuff is needed for SPI driver
|
||||
*/
|
||||
txbuff = spi_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(txbuff);
|
||||
|
||||
h = (struct esp_payload_header *) txbuff;
|
||||
h->if_type = ESP_MAX_IF;
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.spi_mem_stats.tx_dummy_alloc++;
|
||||
#endif
|
||||
tx_buff_free_func = spi_buffer_free;
|
||||
schedule_dummy_tx = 0;
|
||||
} else {
|
||||
schedule_dummy_tx = 1;
|
||||
ESP_HEXLOGV("h_spi_tx", txbuff, 16);
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "dr %u tx_valid %u\n", gpio_rx_data_ready, is_valid_tx_buf);
|
||||
/* Allocate rx buffer */
|
||||
rxbuff = spi_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(rxbuff);
|
||||
//heap_caps_dump_all();
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.spi_mem_stats.rx_alloc++;
|
||||
#endif
|
||||
|
||||
spi_trans.tx_buf = txbuff;
|
||||
spi_trans.tx_buf_size = MAX_SPI_BUFFER_SIZE;
|
||||
spi_trans.rx_buf = rxbuff;
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
struct esp_payload_header *payload_header =
|
||||
(struct esp_payload_header *) txbuff;
|
||||
if (payload_header->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_out++;
|
||||
#endif
|
||||
|
||||
/* Execute transaction only if EITHER holds true-
|
||||
* a. A valid tx buffer to be transmitted towards slave
|
||||
* b. Slave wants to send something (Rx for host)
|
||||
*/
|
||||
ret = g_h.funcs->_h_do_bus_transfer(&spi_trans);
|
||||
|
||||
if (!ret)
|
||||
process_spi_rx_buf(spi_trans.rx_buf);
|
||||
}
|
||||
|
||||
if (txbuff && tx_buff_free_func) {
|
||||
tx_buff_free_func(txbuff);
|
||||
#if H_MEM_STATS
|
||||
if (tx_buff_free_func == spi_buffer_free)
|
||||
h_stats_g.spi_mem_stats.tx_freed++;
|
||||
else
|
||||
h_stats_g.others.tx_others_freed++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if ((gpio_handshake != H_HS_VAL_ACTIVE) || schedule_dummy_tx || schedule_dummy_rx)
|
||||
g_h.funcs->_h_post_semaphore(spi_trans_ready_sem);
|
||||
|
||||
g_h.funcs->_h_unlock_mutex(spi_bus_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send to slave via SPI
|
||||
* @param iface_type -type of interface
|
||||
* iface_num - interface number
|
||||
* wbuffer - tx buffer
|
||||
* wlen - size of wbuffer
|
||||
* @retval sendbuf - Tx buffer
|
||||
*/
|
||||
int esp_hosted_tx(uint8_t iface_type, uint8_t iface_num,
|
||||
uint8_t * wbuffer, uint16_t wlen, uint8_t buff_zcopy, void (*free_wbuf_fun)(void* ptr))
|
||||
{
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
void (*free_func)(void* ptr) = NULL;
|
||||
uint8_t transport_up = is_transport_tx_ready();
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
|
||||
if (free_wbuf_fun)
|
||||
free_func = free_wbuf_fun;
|
||||
|
||||
if (!wbuffer || !wlen || (wlen > MAX_PAYLOAD_SIZE) || !transport_up) {
|
||||
ESP_LOGE(TAG, "write fail: trans_ready[%u] buff(%p) 0? OR (0<len(%u)<=max_poss_len(%u))?",
|
||||
transport_up, wbuffer, wlen, MAX_PAYLOAD_SIZE);
|
||||
H_FREE_PTR_WITH_FUNC(free_func, wbuffer);
|
||||
return STM_FAIL;
|
||||
}
|
||||
//g_h.funcs->_h_memset(&buf_handle, 0, sizeof(buf_handle));
|
||||
buf_handle.payload_zcopy = buff_zcopy;
|
||||
buf_handle.if_type = iface_type;
|
||||
buf_handle.if_num = iface_num;
|
||||
buf_handle.payload_len = wlen;
|
||||
buf_handle.payload = wbuffer;
|
||||
buf_handle.priv_buffer_handle = wbuffer;
|
||||
buf_handle.free_buf_handle = free_func;
|
||||
|
||||
ESP_LOGV(TAG, "ifype: %u wbuff:%p, free: %p wlen:%u ", iface_type, wbuffer, free_func, wlen);
|
||||
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
/* else OTHERS by default */
|
||||
|
||||
g_h.funcs->_h_queue_item(to_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_to_slave_queue);
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_in_pass++;
|
||||
#endif
|
||||
|
||||
#if DEBUG_HOST_TX_SEMAPHORE
|
||||
if (H_DEBUG_GPIO_PIN_Host_Tx_Pin != -1)
|
||||
g_h.funcs->_h_write_gpio(H_DEBUG_GPIO_PIN_Host_Tx_Port, H_DEBUG_GPIO_PIN_Host_Tx_Pin, H_GPIO_HIGH);
|
||||
#endif
|
||||
g_h.funcs->_h_post_semaphore(spi_trans_ready_sem);
|
||||
|
||||
return STM_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Local Functions **/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Task for SPI transaction
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
static void spi_transaction_task(void const* pvParameters)
|
||||
{
|
||||
|
||||
ESP_LOGD(TAG, "Staring SPI task");
|
||||
#if DEBUG_HOST_TX_SEMAPHORE
|
||||
if (H_DEBUG_GPIO_PIN_Host_Tx_Pin != -1)
|
||||
g_h.funcs->_h_config_gpio(H_DEBUG_GPIO_PIN_Host_Tx_Port, H_DEBUG_GPIO_PIN_Host_Tx_Pin, H_GPIO_MODE_DEF_OUTPUT);
|
||||
#endif
|
||||
|
||||
g_h.funcs->_h_config_gpio_as_interrupt(H_GPIO_HANDSHAKE_Port, H_GPIO_HANDSHAKE_Pin,
|
||||
H_HS_INTR_EDGE, gpio_hs_isr_handler);
|
||||
|
||||
g_h.funcs->_h_config_gpio_as_interrupt(H_GPIO_DATA_READY_Port, H_GPIO_DATA_READY_Pin,
|
||||
H_DR_INTR_EDGE, gpio_dr_isr_handler);
|
||||
|
||||
#if !H_HANDSHAKE_ACTIVE_HIGH
|
||||
ESP_LOGI(TAG, "Handshake: Active Low");
|
||||
#endif
|
||||
#if !H_DATAREADY_ACTIVE_HIGH
|
||||
ESP_LOGI(TAG, "DataReady: Active Low");
|
||||
#endif
|
||||
|
||||
ESP_LOGD(TAG, "SPI GPIOs configured");
|
||||
|
||||
create_debugging_tasks();
|
||||
|
||||
for (;;) {
|
||||
|
||||
if ((!is_transport_rx_ready()) ||
|
||||
(!spi_trans_ready_sem)) {
|
||||
g_h.funcs->_h_msleep(300);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do SPI transactions unless first event is received.
|
||||
* Then onward only do transactions if ESP sends interrupt
|
||||
* on Either Data ready and Handshake pin
|
||||
*/
|
||||
|
||||
if (!g_h.funcs->_h_get_semaphore(spi_trans_ready_sem, HOSTED_BLOCK_MAX)) {
|
||||
#if DEBUG_HOST_TX_SEMAPHORE
|
||||
if (H_DEBUG_GPIO_PIN_Host_Tx_Pin != -1)
|
||||
g_h.funcs->_h_write_gpio(H_DEBUG_GPIO_PIN_Host_Tx_Port, H_DEBUG_GPIO_PIN_Host_Tx_Pin, H_GPIO_LOW);
|
||||
#endif
|
||||
|
||||
check_and_execute_spi_transaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RX processing task
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
static void spi_process_rx_task(void const* pvParameters)
|
||||
{
|
||||
interface_buffer_handle_t buf_handle_l = {0};
|
||||
interface_buffer_handle_t *buf_handle = NULL;
|
||||
int ret = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
g_h.funcs->_h_get_semaphore(sem_from_slave_queue, HOSTED_BLOCK_MAX);
|
||||
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_SERIAL], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_BT], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_OTHERS], &buf_handle_l, 0)) {
|
||||
ESP_LOGI(TAG, "No element in any queue found");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf_handle = &buf_handle_l;
|
||||
|
||||
struct esp_priv_event *event = NULL;
|
||||
|
||||
/* process received buffer for all possible interface types */
|
||||
if (buf_handle->if_type == ESP_SERIAL_IF) {
|
||||
|
||||
/* serial interface path */
|
||||
serial_rx_handler(buf_handle);
|
||||
|
||||
} else if((buf_handle->if_type == ESP_STA_IF) ||
|
||||
(buf_handle->if_type == ESP_AP_IF)) {
|
||||
schedule_dummy_rx = 1;
|
||||
#if 1
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
/* TODO : Need to abstract heap_caps_malloc */
|
||||
uint8_t * copy_payload = (uint8_t *)g_h.funcs->_h_malloc(buf_handle->payload_len);
|
||||
assert(copy_payload);
|
||||
memcpy(copy_payload, buf_handle->payload, buf_handle->payload_len);
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle, buf_handle->priv_buffer_handle);
|
||||
|
||||
ret = chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
copy_payload, copy_payload, buf_handle->payload_len);
|
||||
if (unlikely(ret))
|
||||
HOSTED_FREE(copy_payload);
|
||||
}
|
||||
#else
|
||||
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
buf_handle->payload, NULL, buf_handle->payload_len);
|
||||
}
|
||||
#endif
|
||||
} else if (buf_handle->if_type == ESP_PRIV_IF) {
|
||||
process_priv_communication(buf_handle);
|
||||
hci_drv_show_configuration();
|
||||
/* priv transaction received */
|
||||
ESP_LOGI(TAG, "Received INIT event");
|
||||
|
||||
event = (struct esp_priv_event *) (buf_handle->payload);
|
||||
if (event->event_type != ESP_PRIV_EVENT_INIT) {
|
||||
/* User can re-use this type of transaction */
|
||||
}
|
||||
} else if (buf_handle->if_type == ESP_HCI_IF) {
|
||||
hci_rx_handler(buf_handle);
|
||||
} else if (buf_handle->if_type == ESP_TEST_IF) {
|
||||
#if TEST_RAW_TP
|
||||
update_test_raw_tp_rx_len(buf_handle->payload_len+H_ESP_PAYLOAD_HEADER_OFFSET);
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unknown type %d ", buf_handle->if_type);
|
||||
}
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_out++;
|
||||
#endif
|
||||
|
||||
/* Free buffer handle */
|
||||
/* When buffer offloaded to other module, that module is
|
||||
* responsible for freeing buffer. In case not offloaded or
|
||||
* failed to offload, buffer should be freed here.
|
||||
*/
|
||||
if (!buf_handle->payload_zcopy) {
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle,buf_handle->priv_buffer_handle);
|
||||
#if H_MEM_STATS
|
||||
if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
|
||||
if (spi_buffer_free == buf_handle->free_buf_handle)
|
||||
h_stats_g.spi_mem_stats.rx_freed++;
|
||||
else
|
||||
h_stats_g.others.tx_others_freed++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Next TX buffer in SPI transaction
|
||||
* @param argument: Not used
|
||||
* @retval sendbuf - Tx buffer
|
||||
*/
|
||||
static uint8_t * get_next_tx_buffer(uint8_t *is_valid_tx_buf, void (**free_func)(void* ptr))
|
||||
{
|
||||
struct esp_payload_header *payload_header;
|
||||
uint8_t *sendbuf = NULL;
|
||||
uint8_t *payload = NULL;
|
||||
uint16_t len = 0;
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
uint8_t tx_needed = 1;
|
||||
|
||||
assert(is_valid_tx_buf);
|
||||
assert(free_func);
|
||||
|
||||
*is_valid_tx_buf = 0;
|
||||
|
||||
/* Check if higher layers have anything to transmit, non blocking.
|
||||
* If nothing is expected to send, queue receive will fail.
|
||||
* In that case only payload header with zero payload
|
||||
* length would be transmitted.
|
||||
*/
|
||||
|
||||
if (!g_h.funcs->_h_get_semaphore(sem_to_slave_queue, 0)) {
|
||||
|
||||
/* Tx msg is present as per sem */
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_SERIAL], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_BT], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_OTHERS], &buf_handle, 0)) {
|
||||
tx_needed = 0; /* No Tx msg */
|
||||
}
|
||||
|
||||
if (tx_needed)
|
||||
len = buf_handle.payload_len;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
|
||||
ESP_HEXLOGD("h_spi_tx", buf_handle.payload, 16);
|
||||
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
sendbuf = spi_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(sendbuf);
|
||||
#if H_MEM_STATS
|
||||
h_stats_g.spi_mem_stats.tx_alloc++;
|
||||
#endif
|
||||
*free_func = spi_buffer_free;
|
||||
} else {
|
||||
sendbuf = buf_handle.payload;
|
||||
*free_func = buf_handle.free_buf_handle;
|
||||
}
|
||||
|
||||
if (!sendbuf) {
|
||||
ESP_LOGE(TAG, "spi buff malloc failed");
|
||||
*free_func = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//g_h.funcs->_h_memset(sendbuf, 0, MAX_SPI_BUFFER_SIZE);
|
||||
|
||||
*is_valid_tx_buf = 1;
|
||||
|
||||
/* Form Tx header */
|
||||
payload_header = (struct esp_payload_header *) sendbuf;
|
||||
payload = sendbuf + sizeof(struct esp_payload_header);
|
||||
payload_header->len = htole16(len);
|
||||
payload_header->offset = htole16(sizeof(struct esp_payload_header));
|
||||
payload_header->if_type = buf_handle.if_type;
|
||||
payload_header->if_num = buf_handle.if_num;
|
||||
|
||||
if (payload_header->if_type == ESP_HCI_IF) {
|
||||
// special handling for HCI
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
// copy first byte of payload into header
|
||||
payload_header->hci_pkt_type = buf_handle.payload[0];
|
||||
// adjust actual payload len
|
||||
len -= 1;
|
||||
payload_header->len = htole16(len);
|
||||
g_h.funcs->_h_memcpy(payload, &buf_handle.payload[1], len);
|
||||
}
|
||||
} else
|
||||
if (!buf_handle.payload_zcopy)
|
||||
g_h.funcs->_h_memcpy(payload, buf_handle.payload, min(len, MAX_PAYLOAD_SIZE));
|
||||
|
||||
//TODO: checksum should be configurable from menuconfig
|
||||
payload_header->checksum = htole16(compute_checksum(sendbuf,
|
||||
sizeof(struct esp_payload_header)+len));
|
||||
}
|
||||
|
||||
done:
|
||||
if (len && !buf_handle.payload_zcopy) {
|
||||
/* free allocated buffer, only if zerocopy is not requested */
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle.free_buf_handle, buf_handle.priv_buffer_handle);
|
||||
#if H_MEM_STATS
|
||||
if (buf_handle.free_buf_handle &&
|
||||
buf_handle.priv_buffer_handle &&
|
||||
((buf_handle.if_type == ESP_STA_IF) || (buf_handle.if_type == ESP_AP_IF))) {
|
||||
h_stats_g.nw_mem_stats.tx_freed++;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return sendbuf;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __SPI_DRV_H
|
||||
#define __SPI_DRV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Includes **/
|
||||
#include "common.h"
|
||||
#include "transport_drv.h"
|
||||
#include "os_wrapper.h"
|
||||
|
||||
|
||||
/** Constants/Macros **/
|
||||
#define TO_SLAVE_QUEUE_SIZE 20
|
||||
#define FROM_SLAVE_QUEUE_SIZE 20
|
||||
|
||||
/** Exported Structures **/
|
||||
|
||||
/** Exported variables **/
|
||||
|
||||
/** Inline functions **/
|
||||
|
||||
/** Exported Functions **/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,767 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <stdint.h>
|
||||
|
||||
#include "drivers/bt/hci_drv.h"
|
||||
|
||||
#include "endian.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_transport_spi_hd.h"
|
||||
#include "stats.h"
|
||||
#include "transport_drv.h"
|
||||
|
||||
#include "spi_hd_drv.h"
|
||||
#include "esp_hosted_config.h"
|
||||
|
||||
#include "esp_hosted_log.h"
|
||||
static const char TAG[] = "H_SPI_HD_DRV";
|
||||
|
||||
// this locks the spi_hd transaction at the driver level, instead of at the HAL layer
|
||||
#define USE_DRIVER_LOCK (1)
|
||||
|
||||
#if USE_DRIVER_LOCK
|
||||
#define ACQUIRE_LOCK false
|
||||
#else
|
||||
#define ACQUIRE_LOCK true
|
||||
#endif
|
||||
|
||||
// some SPI HD slave registers must be polled (read multiple times)
|
||||
// to get a stable value as slave may update the data while the
|
||||
// host is reading the register
|
||||
#define POLLING_READ 3 // retry this amount of times
|
||||
#define NO_POLLING_READ 0 // read once only, no retries
|
||||
|
||||
#if USE_DRIVER_LOCK
|
||||
static void * spi_hd_bus_lock;
|
||||
|
||||
#define SPI_HD_DRV_LOCK_CREATE() do { \
|
||||
spi_hd_bus_lock = g_h.funcs->_h_create_mutex(); \
|
||||
assert(spi_hd_bus_lock); \
|
||||
} while (0);
|
||||
#define SPI_HD_DRV_LOCK_DESTROY() do { \
|
||||
g_h.funcs->_h_destroy_mutex(spi_hd_bus_lock); \
|
||||
} while (0);
|
||||
|
||||
#define SPI_HD_DRV_LOCK() g_h.funcs->_h_lock_mutex(spi_hd_bus_lock, HOSTED_BLOCK_MAX);
|
||||
#define SPI_HD_DRV_UNLOCK() g_h.funcs->_h_unlock_mutex(spi_hd_bus_lock);
|
||||
|
||||
#else
|
||||
#define SPI_HD_DRV_LOCK_CREATE()
|
||||
#define SPI_HD_DRV_LOCK_DESTROY()
|
||||
#define SPI_HD_DRV_LOCK()
|
||||
#define SPI_HD_DRV_UNLOCK()
|
||||
#endif
|
||||
|
||||
#define BUFFER_AVAILABLE 1
|
||||
#define BUFFER_UNAVAILABLE 0
|
||||
|
||||
// max number of time to try to read write buffer available reg
|
||||
#define MAX_WRITE_BUF_RETRIES 25
|
||||
|
||||
/* Create mempool for cache mallocs */
|
||||
static struct mempool * buf_mp_g;
|
||||
|
||||
/* TODO to move this in transport drv */
|
||||
extern transport_channel_t *chan_arr[ESP_MAX_IF];
|
||||
|
||||
static void * spi_hd_handle = NULL;
|
||||
static void * spi_hd_read_thread;
|
||||
static void * spi_hd_process_rx_thread;
|
||||
static void * spi_hd_write_thread;
|
||||
|
||||
static queue_handle_t to_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
static semaphore_handle_t sem_to_slave_queue;
|
||||
static queue_handle_t from_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
static semaphore_handle_t sem_from_slave_queue;
|
||||
static semaphore_handle_t spi_hd_data_ready_sem;
|
||||
|
||||
/* Counter to hold the amount of buffers already sent to spi hd slave */
|
||||
static uint32_t spi_hd_tx_buf_count = 0;
|
||||
|
||||
/* Counter to hold the amount of bytes already received from spi hd slave */
|
||||
static uint32_t spi_hd_rx_byte_count = 0;
|
||||
|
||||
// one-time trigger to start write thread
|
||||
static bool spi_hd_start_write_thread = false;
|
||||
|
||||
static void spi_hd_write_task(void const* pvParameters);
|
||||
static void spi_hd_read_task(void const* pvParameters);
|
||||
static void spi_hd_process_rx_task(void const* pvParameters);
|
||||
static int update_flow_ctrl(uint8_t *rxbuff);
|
||||
|
||||
static inline void spi_hd_mempool_create()
|
||||
{
|
||||
MEM_DUMP("spi_hd_mempool_create");
|
||||
buf_mp_g = mempool_create(MAX_SPI_HD_BUFFER_SIZE);
|
||||
#ifdef H_USE_MEMPOOL
|
||||
assert(buf_mp_g);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void spi_hd_mempool_destroy()
|
||||
{
|
||||
mempool_destroy(buf_mp_g);
|
||||
}
|
||||
|
||||
static inline void *spi_hd_buffer_alloc(uint need_memset)
|
||||
{
|
||||
return mempool_alloc(buf_mp_g, MAX_SPI_HD_BUFFER_SIZE, need_memset);
|
||||
}
|
||||
|
||||
static inline void spi_hd_buffer_free(void *buf)
|
||||
{
|
||||
mempool_free(buf_mp_g, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* This ISR is called when the data_ready line goes high.
|
||||
*/
|
||||
static void FAST_RAM_ATTR gpio_dr_isr_handler(void* arg)
|
||||
{
|
||||
g_h.funcs->_h_post_semaphore_from_isr(spi_hd_data_ready_sem);
|
||||
}
|
||||
|
||||
static int spi_hd_get_tx_buffer_num(uint32_t *tx_num, bool is_lock_needed)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = g_h.funcs->_h_spi_hd_read_reg(SPI_HD_REG_RX_BUF_LEN, &len, POLLING_READ, is_lock_needed);
|
||||
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s: err: %"PRIi16, __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// see spi_hd_read_task() for explanation on how this is safe during overflow
|
||||
*tx_num = len - spi_hd_tx_buf_count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_hd_is_write_buffer_available(uint32_t buf_needed)
|
||||
{
|
||||
static uint32_t buf_available = 0;
|
||||
uint8_t retry = MAX_WRITE_BUF_RETRIES;
|
||||
|
||||
/* If buffer needed are less than buffer available
|
||||
then only read for available buffer number from slave*/
|
||||
if (buf_available < buf_needed) {
|
||||
while (retry) {
|
||||
spi_hd_get_tx_buffer_num(&buf_available, ACQUIRE_LOCK);
|
||||
if (buf_available < buf_needed) {
|
||||
ESP_LOGV(TAG, "Retry get write buffers %d", retry);
|
||||
retry--;
|
||||
|
||||
if (retry < MAX_WRITE_BUF_RETRIES)
|
||||
g_h.funcs->_h_msleep(1);
|
||||
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_available >= buf_needed)
|
||||
buf_available -= buf_needed;
|
||||
|
||||
if (!retry) {
|
||||
/* No buffer available at slave */
|
||||
return BUFFER_UNAVAILABLE;
|
||||
}
|
||||
|
||||
return BUFFER_AVAILABLE;
|
||||
}
|
||||
|
||||
static void spi_hd_write_task(void const* pvParameters)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
uint8_t *sendbuf = NULL;
|
||||
void (*free_func)(void* ptr) = NULL;
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
uint8_t * payload = NULL;
|
||||
struct esp_payload_header * payload_header = NULL;
|
||||
|
||||
int ret = 0;
|
||||
uint32_t data_left;
|
||||
uint32_t buf_needed;
|
||||
uint8_t tx_needed = 1;
|
||||
|
||||
while (!spi_hd_start_write_thread)
|
||||
g_h.funcs->_h_msleep(10);
|
||||
|
||||
for (;;) {
|
||||
/* Check if higher layers have anything to transmit */
|
||||
g_h.funcs->_h_get_semaphore(sem_to_slave_queue, HOSTED_BLOCK_MAX);
|
||||
|
||||
/* Tx msg is present as per sem */
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_SERIAL], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_BT], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_OTHERS], &buf_handle, 0)) {
|
||||
tx_needed = 0; /* No Tx msg */
|
||||
}
|
||||
|
||||
if (tx_needed)
|
||||
len = buf_handle.payload_len;
|
||||
|
||||
if (!len) {
|
||||
ESP_LOGE(TAG, "%s: Empty len", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
sendbuf = spi_hd_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(sendbuf);
|
||||
free_func = spi_hd_buffer_free;
|
||||
} else {
|
||||
sendbuf = buf_handle.payload;
|
||||
free_func = buf_handle.free_buf_handle;
|
||||
}
|
||||
|
||||
if (!sendbuf) {
|
||||
ESP_LOGE(TAG, "spi_hd buff malloc failed");
|
||||
free_func = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (buf_handle.payload_len > MAX_SPI_HD_BUFFER_SIZE - sizeof(struct esp_payload_header)) {
|
||||
ESP_LOGE(TAG, "Pkt len [%u] > Max [%u]. Drop",
|
||||
buf_handle.payload_len, MAX_SPI_HD_BUFFER_SIZE - sizeof(struct esp_payload_header));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Form Tx header */
|
||||
payload_header = (struct esp_payload_header *) sendbuf;
|
||||
payload = sendbuf + sizeof(struct esp_payload_header);
|
||||
|
||||
payload_header->len = htole16(len);
|
||||
payload_header->offset = htole16(sizeof(struct esp_payload_header));
|
||||
payload_header->if_type = buf_handle.if_type;
|
||||
payload_header->if_num = buf_handle.if_num;
|
||||
payload_header->seq_num = htole16(buf_handle.seq_num);
|
||||
payload_header->flags = buf_handle.flag;
|
||||
|
||||
if (payload_header->if_type == ESP_HCI_IF) {
|
||||
// special handling for HCI
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
// copy first byte of payload into header
|
||||
payload_header->hci_pkt_type = buf_handle.payload[0];
|
||||
// adjust actual payload len
|
||||
len -= 1;
|
||||
payload_header->len = htole16(len);
|
||||
g_h.funcs->_h_memcpy(payload, &buf_handle.payload[1], len);
|
||||
}
|
||||
} else
|
||||
if (!buf_handle.payload_zcopy)
|
||||
g_h.funcs->_h_memcpy(payload, buf_handle.payload, len);
|
||||
|
||||
#if H_SPI_HD_CHECKSUM
|
||||
payload_header->checksum = htole16(compute_checksum(sendbuf,
|
||||
sizeof(struct esp_payload_header) + len));
|
||||
#endif
|
||||
|
||||
buf_needed = (len + sizeof(struct esp_payload_header) + MAX_SPI_HD_BUFFER_SIZE - 1)
|
||||
/ MAX_SPI_HD_BUFFER_SIZE;
|
||||
|
||||
SPI_HD_DRV_LOCK();
|
||||
|
||||
// ESP_LOGW(TAG, "spi_hd_is_write_buffer_available()");
|
||||
ret = spi_hd_is_write_buffer_available(buf_needed);
|
||||
if (ret != BUFFER_AVAILABLE) {
|
||||
ESP_LOGV(TAG, "no SPI_HD write buffers on slave device");
|
||||
goto unlock_done;
|
||||
}
|
||||
|
||||
data_left = len + sizeof(struct esp_payload_header);
|
||||
|
||||
ESP_HEXLOGV("h_spi_hd_tx", sendbuf, data_left);
|
||||
|
||||
ret = g_h.funcs->_h_spi_hd_write_dma(sendbuf, data_left, ACQUIRE_LOCK);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send data", __func__);
|
||||
goto unlock_done;
|
||||
}
|
||||
|
||||
spi_hd_tx_buf_count += buf_needed;
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_out++;
|
||||
#endif
|
||||
|
||||
unlock_done:
|
||||
SPI_HD_DRV_UNLOCK();
|
||||
done:
|
||||
if (len && !buf_handle.payload_zcopy) {
|
||||
/* free allocated buffer, only if zerocopy is not requested */
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle.free_buf_handle, buf_handle.priv_buffer_handle);
|
||||
}
|
||||
H_FREE_PTR_WITH_FUNC(free_func, sendbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static int is_valid_spi_hd_rx_packet(uint8_t *rxbuff_a, uint16_t *len_a, uint16_t *offset_a)
|
||||
{
|
||||
struct esp_payload_header * h = (struct esp_payload_header *)rxbuff_a;
|
||||
uint16_t len = 0, offset = 0;
|
||||
#if H_SPI_HD_CHECKSUM
|
||||
uint16_t rx_checksum = 0, checksum = 0;
|
||||
#endif
|
||||
|
||||
if (!h || !len_a || !offset_a)
|
||||
return 0;
|
||||
|
||||
/* Fetch length and offset from payload header */
|
||||
len = le16toh(h->len);
|
||||
offset = le16toh(h->offset);
|
||||
|
||||
if ((!len) ||
|
||||
(len > MAX_PAYLOAD_SIZE) ||
|
||||
(offset != sizeof(struct esp_payload_header))) {
|
||||
|
||||
/* Free up buffer, as one of following -
|
||||
* 1. no payload to process
|
||||
* 2. input packet size > driver capacity
|
||||
* 3. payload header size mismatch,
|
||||
* wrong header/bit packing?
|
||||
* */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#if H_SPI_HD_CHECKSUM
|
||||
rx_checksum = le16toh(h->checksum);
|
||||
h->checksum = 0;
|
||||
checksum = compute_checksum((uint8_t*)h, len + offset);
|
||||
|
||||
if (checksum != rx_checksum) {
|
||||
ESP_LOGE(TAG, "SPI_HD RX rx_chksum[%u] != checksum[%u]. Drop.",
|
||||
checksum, rx_checksum);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (h->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_in++;
|
||||
#endif
|
||||
|
||||
*len_a = len;
|
||||
*offset_a = offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int update_flow_ctrl(uint8_t *rxbuff)
|
||||
{
|
||||
struct esp_payload_header * h = (struct esp_payload_header *)rxbuff;
|
||||
if (h->throttle_cmd) {
|
||||
if (h->throttle_cmd == H_FLOW_CTRL_ON) {
|
||||
wifi_tx_throttling = 1;
|
||||
}
|
||||
if (h->throttle_cmd == H_FLOW_CTRL_OFF) {
|
||||
wifi_tx_throttling = 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// pushes received packet data on to rx queue
|
||||
static esp_err_t spi_hd_push_pkt_to_queue(uint8_t * rxbuff, uint16_t len, uint16_t offset)
|
||||
{
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
struct esp_payload_header *h= NULL;
|
||||
interface_buffer_handle_t buf_handle;
|
||||
|
||||
h = (struct esp_payload_header *)rxbuff;
|
||||
|
||||
memset(&buf_handle, 0, sizeof(interface_buffer_handle_t));
|
||||
|
||||
buf_handle.priv_buffer_handle = rxbuff;
|
||||
buf_handle.free_buf_handle = spi_hd_buffer_free;
|
||||
buf_handle.payload_len = len;
|
||||
buf_handle.if_type = h->if_type;
|
||||
buf_handle.if_num = h->if_num;
|
||||
buf_handle.payload = rxbuff + offset;
|
||||
buf_handle.seq_num = le16toh(h->seq_num);
|
||||
buf_handle.flag = h->flags;
|
||||
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
/* else OTHERS by default */
|
||||
|
||||
g_h.funcs->_h_queue_item(from_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_from_slave_queue);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t spi_hd_push_data_to_queue(uint8_t * buf, uint32_t buf_len)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
uint16_t offset = 0;
|
||||
|
||||
if (update_flow_ctrl(buf)) {
|
||||
// detected and updated flow control
|
||||
// no need to further process the packet
|
||||
HOSTED_FREE(buf);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Drop packet if no processing needed */
|
||||
if (!is_valid_spi_hd_rx_packet(buf, &len, &offset)) {
|
||||
/* Free up buffer, as one of following -
|
||||
* 1. no payload to process
|
||||
* 2. input packet size > driver capacity
|
||||
* 3. payload header size mismatch,
|
||||
* wrong header/bit packing?
|
||||
* */
|
||||
ESP_LOGE(TAG, "Dropping packet");
|
||||
HOSTED_FREE(buf);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (spi_hd_push_pkt_to_queue(buf, len, offset)) {
|
||||
ESP_LOGE(TAG, "Failed to push Rx packet to queue");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void spi_hd_read_task(void const* pvParameters)
|
||||
{
|
||||
int res;
|
||||
uint8_t *rxbuff = NULL;
|
||||
uint32_t data;
|
||||
uint32_t curr_rx_value;
|
||||
uint32_t size_to_xfer;
|
||||
uint32_t int_mask;
|
||||
|
||||
ESP_LOGV(TAG, "%s: waiting for transport to be in reset state", __func__);
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (is_transport_rx_ready()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check that slave is ready
|
||||
while (true) {
|
||||
res = g_h.funcs->_h_spi_hd_read_reg(SPI_HD_REG_SLAVE_READY, &data, POLLING_READ, ACQUIRE_LOCK);
|
||||
if (res) {
|
||||
ESP_LOGE(TAG, "Error reading slave register");
|
||||
}
|
||||
else if (data == SPI_HD_STATE_SLAVE_READY) {
|
||||
ESP_LOGV(TAG, "Slave is ready");
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
create_debugging_tasks();
|
||||
|
||||
// slave is ready: initialise Data Ready as interrupt input
|
||||
g_h.funcs->_h_config_gpio_as_interrupt(H_SPI_HD_GPIO_DATA_READY_Port, H_SPI_HD_PIN_DATA_READY,
|
||||
H_SPI_HD_DR_INTR_EDGE, gpio_dr_isr_handler);
|
||||
|
||||
// tell slave to open data path
|
||||
data = SPI_HD_CTRL_DATAPATH_ON;
|
||||
g_h.funcs->_h_spi_hd_write_reg(SPI_HD_REG_SLAVE_CTRL, &data, ACQUIRE_LOCK);
|
||||
|
||||
// we are now ready to receive data from slave
|
||||
while (1) {
|
||||
// wait for read semaphore to trigger
|
||||
g_h.funcs->_h_get_semaphore(spi_hd_data_ready_sem, HOSTED_BLOCK_MAX);
|
||||
|
||||
SPI_HD_DRV_LOCK();
|
||||
|
||||
res = g_h.funcs->_h_spi_hd_read_reg(SPI_HD_REG_TX_BUF_LEN, &curr_rx_value, POLLING_READ, ACQUIRE_LOCK);
|
||||
if (res) {
|
||||
ESP_LOGE(TAG, "error reading slave SPI_HD_REG_TX_BUF_LEN register");
|
||||
SPI_HD_DRV_UNLOCK();
|
||||
continue;
|
||||
}
|
||||
|
||||
// send cmd9 to clear the interrupts on the slave
|
||||
g_h.funcs->_h_spi_hd_send_cmd9();
|
||||
|
||||
// save the int mask
|
||||
int_mask = curr_rx_value & SPI_HD_INT_MASK;
|
||||
|
||||
if (int_mask & SPI_HD_INT_START_THROTTLE) {
|
||||
wifi_tx_throttling = 1;
|
||||
}
|
||||
if (int_mask & SPI_HD_INT_STOP_THROTTLE) {
|
||||
wifi_tx_throttling = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the amount of rx data to transfer
|
||||
* this is calculated as the difference between the curr_rx_value
|
||||
* and the spi_hd_rx_byte_count.
|
||||
*
|
||||
* Logic to handle overflow is the same as implemented in
|
||||
* <esp-idf>/examples/peripherals/spi_slave_hd/segment_mode/seg_master/main/app_main.c
|
||||
* as reproduced here:
|
||||
*
|
||||
* Condition when this counter overflows:
|
||||
* If the Slave increases its counter with the value smaller
|
||||
* than 2^32, then the calculation is still safe. For example:
|
||||
* 1. Initially, Slave's counter is (2^32 - 1 - 10), Master's
|
||||
* counter is (2^32 - 1 - 20). So the difference would be 10B
|
||||
* initially.
|
||||
* 2. Slave loads 20 bytes to the DMA, and increase its
|
||||
* counter. So the value would be ((2^32 - 1 - 10) + 20) = 9;
|
||||
* 3. The difference (`size_can_be_read`) would be (9 - (2^32
|
||||
* - 1 - 20)) = 30;
|
||||
*/
|
||||
|
||||
curr_rx_value &= SPI_HD_TX_BUF_LEN_MASK;
|
||||
size_to_xfer = (curr_rx_value - spi_hd_rx_byte_count) & SPI_HD_TX_BUF_LEN_MASK;
|
||||
|
||||
if (!size_to_xfer) {
|
||||
// no data to read
|
||||
// this can happen if slave updates interrupt bits only
|
||||
SPI_HD_DRV_UNLOCK();
|
||||
continue;
|
||||
}
|
||||
|
||||
// allocate rx buffer
|
||||
rxbuff = spi_hd_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(rxbuff);
|
||||
|
||||
// read data
|
||||
res = g_h.funcs->_h_spi_hd_read_dma(rxbuff, size_to_xfer, ACQUIRE_LOCK);
|
||||
|
||||
// update count, taking into account the mask
|
||||
spi_hd_rx_byte_count = (spi_hd_rx_byte_count + size_to_xfer) & SPI_HD_TX_BUF_LEN_MASK;
|
||||
|
||||
SPI_HD_DRV_UNLOCK();
|
||||
|
||||
if (res) {
|
||||
ESP_LOGE(TAG, "error reading data");
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_HEXLOGV("spi_hd_rx", rxbuff, size_to_xfer);
|
||||
|
||||
if (spi_hd_push_data_to_queue(rxbuff, size_to_xfer))
|
||||
ESP_LOGE(TAG, "Failed to push data to rx queue");
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_hd_process_rx_task(void const* pvParameters)
|
||||
{
|
||||
interface_buffer_handle_t buf_handle_l = {0};
|
||||
interface_buffer_handle_t *buf_handle = NULL;
|
||||
int ret = 0;
|
||||
|
||||
struct esp_priv_event *event = NULL;
|
||||
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (is_transport_rx_ready()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
g_h.funcs->_h_get_semaphore(sem_from_slave_queue, HOSTED_BLOCK_MAX);
|
||||
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_SERIAL], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_BT], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_OTHERS], &buf_handle_l, 0)) {
|
||||
ESP_LOGI(TAG, "No element in any queue found");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf_handle = &buf_handle_l;
|
||||
|
||||
ESP_LOGV(TAG, "spi_hd iftype:%d", (int)buf_handle->if_type);
|
||||
ESP_HEXLOGV("rx", buf_handle->payload, buf_handle->payload_len);
|
||||
|
||||
if (buf_handle->if_type == ESP_SERIAL_IF) {
|
||||
/* serial interface path */
|
||||
serial_rx_handler(buf_handle);
|
||||
} else if((buf_handle->if_type == ESP_STA_IF) ||
|
||||
(buf_handle->if_type == ESP_AP_IF)) {
|
||||
#if 1
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
/* TODO : Need to abstract heap_caps_malloc */
|
||||
uint8_t * copy_payload = (uint8_t *)g_h.funcs->_h_malloc(buf_handle->payload_len);
|
||||
assert(copy_payload);
|
||||
assert(buf_handle->payload_len);
|
||||
assert(buf_handle->payload);
|
||||
memcpy(copy_payload, buf_handle->payload, buf_handle->payload_len);
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle, buf_handle->priv_buffer_handle);
|
||||
|
||||
ret = chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
copy_payload, copy_payload, buf_handle->payload_len);
|
||||
if (unlikely(ret))
|
||||
HOSTED_FREE(copy_payload);
|
||||
}
|
||||
#else
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
buf_handle->payload, NULL, buf_handle->payload_len);
|
||||
}
|
||||
#endif
|
||||
} else if (buf_handle->if_type == ESP_PRIV_IF) {
|
||||
process_priv_communication(buf_handle);
|
||||
hci_drv_show_configuration();
|
||||
/* priv transaction received */
|
||||
ESP_LOGI(TAG, "Received INIT event");
|
||||
spi_hd_start_write_thread = true;
|
||||
|
||||
event = (struct esp_priv_event *) (buf_handle->payload);
|
||||
if (event->event_type != ESP_PRIV_EVENT_INIT) {
|
||||
/* User can re-use this type of transaction */
|
||||
}
|
||||
} else if (buf_handle->if_type == ESP_HCI_IF) {
|
||||
hci_rx_handler(buf_handle);
|
||||
} else if (buf_handle->if_type == ESP_TEST_IF) {
|
||||
#if TEST_RAW_TP
|
||||
update_test_raw_tp_rx_len(buf_handle->payload_len +
|
||||
H_ESP_PAYLOAD_HEADER_OFFSET);
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unknown type %d ", buf_handle->if_type);
|
||||
}
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_out++;
|
||||
#endif
|
||||
|
||||
/* Free buffer handle */
|
||||
/* When buffer offloaded to other module, that module is
|
||||
* responsible for freeing buffer. In case not offloaded or
|
||||
* failed to offload, buffer should be freed here.
|
||||
*/
|
||||
if (!buf_handle->payload_zcopy) {
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle,
|
||||
buf_handle->priv_buffer_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transport_init_internal(void)
|
||||
{
|
||||
uint8_t prio_q_idx = 0;
|
||||
|
||||
SPI_HD_DRV_LOCK_CREATE();
|
||||
|
||||
sem_to_slave_queue = g_h.funcs->_h_create_semaphore(H_SPI_HD_TX_QUEUE_SIZE * MAX_PRIORITY_QUEUES);
|
||||
assert(sem_to_slave_queue);
|
||||
g_h.funcs->_h_get_semaphore(sem_to_slave_queue, 0);
|
||||
|
||||
sem_from_slave_queue = g_h.funcs->_h_create_semaphore(H_SPI_HD_RX_QUEUE_SIZE * MAX_PRIORITY_QUEUES);
|
||||
assert(sem_from_slave_queue);
|
||||
g_h.funcs->_h_get_semaphore(sem_from_slave_queue, 0);
|
||||
|
||||
spi_hd_data_ready_sem = g_h.funcs->_h_create_semaphore(H_SPI_HD_RX_QUEUE_SIZE * MAX_PRIORITY_QUEUES);
|
||||
assert(spi_hd_data_ready_sem);
|
||||
g_h.funcs->_h_get_semaphore(spi_hd_data_ready_sem, 0);
|
||||
|
||||
/* cleanup the semaphores */
|
||||
for (prio_q_idx = 0; prio_q_idx < MAX_PRIORITY_QUEUES; prio_q_idx++) {
|
||||
/* Queue - rx */
|
||||
from_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(H_SPI_HD_RX_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(from_slave_queue[prio_q_idx]);
|
||||
|
||||
/* Queue - tx */
|
||||
to_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(H_SPI_HD_TX_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(to_slave_queue[prio_q_idx]);
|
||||
}
|
||||
|
||||
spi_hd_mempool_create();
|
||||
|
||||
spi_hd_read_thread = g_h.funcs->_h_thread_create("spi_hd_read",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, spi_hd_read_task, NULL);
|
||||
|
||||
spi_hd_process_rx_thread = g_h.funcs->_h_thread_create("spi_hd_process_rx",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, spi_hd_process_rx_task, NULL);
|
||||
|
||||
spi_hd_write_thread = g_h.funcs->_h_thread_create("spi_hd_write",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, spi_hd_write_task, NULL);
|
||||
|
||||
spi_hd_handle = g_h.funcs->_h_bus_init();
|
||||
if (!spi_hd_handle) {
|
||||
ESP_LOGE(TAG, "could not create spi_hd handle, exiting\n");
|
||||
assert(spi_hd_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void transport_deinit_internal(void)
|
||||
{
|
||||
/* TODO */
|
||||
|
||||
SPI_HD_DRV_LOCK_DESTROY();
|
||||
}
|
||||
|
||||
int esp_hosted_tx(uint8_t iface_type, uint8_t iface_num,
|
||||
uint8_t * wbuffer, uint16_t wlen, uint8_t buff_zcopy,
|
||||
void (*free_wbuf_fun)(void* ptr))
|
||||
{
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
void (*free_func)(void* ptr) = NULL;
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
uint8_t transport_up = is_transport_tx_ready();
|
||||
|
||||
// ESP_LOGW(TAG, "%s, %"PRIu8, __func__, transport_up);
|
||||
|
||||
if (free_wbuf_fun)
|
||||
free_func = free_wbuf_fun;
|
||||
|
||||
if (!wbuffer || !wlen ||
|
||||
(wlen > MAX_PAYLOAD_SIZE) ||
|
||||
!transport_up) {
|
||||
ESP_LOGE(TAG, "tx fail: NULL buff, invalid len (%u) or len > max len (%u), transport_up(%u))",
|
||||
wlen, MAX_PAYLOAD_SIZE, transport_up);
|
||||
H_FREE_PTR_WITH_FUNC(free_func, wbuffer);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
buf_handle.payload_zcopy = buff_zcopy;
|
||||
buf_handle.if_type = iface_type;
|
||||
buf_handle.if_num = iface_num;
|
||||
buf_handle.payload_len = wlen;
|
||||
buf_handle.payload = wbuffer;
|
||||
buf_handle.priv_buffer_handle = wbuffer;
|
||||
buf_handle.free_buf_handle = free_func;
|
||||
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
|
||||
g_h.funcs->_h_queue_item(to_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_to_slave_queue);
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_in_pass++;
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __SPI_HD_DRV_H
|
||||
#define __SPI_HD_DRV_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#endif /* __SPI_HD_DRV_H */
|
||||
@@ -0,0 +1,666 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <inttypes.h>
|
||||
|
||||
#include "esp_wifi.h"
|
||||
#include "transport_drv.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_transport_init.h"
|
||||
#include "esp_hosted_transport_config.h"
|
||||
#include "stats.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_log.h"
|
||||
#include "serial_drv.h"
|
||||
#include "serial_ll_if.h"
|
||||
#include "esp_hosted_config.h"
|
||||
#include "mempool.h"
|
||||
#include "stats.h"
|
||||
#include "errno.h"
|
||||
#include "hci_drv.h"
|
||||
|
||||
/**
|
||||
* @brief Slave capabilities are parsed
|
||||
* Currently no added functionality to that
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
|
||||
DEFINE_LOG_TAG(transport);
|
||||
static char chip_type = ESP_PRIV_FIRMWARE_CHIP_UNRECOGNIZED;
|
||||
void(*transport_esp_hosted_up_cb)(void) = NULL;
|
||||
transport_channel_t *chan_arr[ESP_MAX_IF];
|
||||
volatile uint8_t wifi_tx_throttling;
|
||||
|
||||
|
||||
static uint8_t transport_state = TRANSPORT_INACTIVE;
|
||||
|
||||
static void process_event(uint8_t *evt_buf, uint16_t len);
|
||||
|
||||
|
||||
uint8_t is_transport_rx_ready(void)
|
||||
{
|
||||
return (transport_state >= TRANSPORT_RX_ACTIVE);
|
||||
}
|
||||
|
||||
uint8_t is_transport_tx_ready(void)
|
||||
{
|
||||
return (transport_state >= TRANSPORT_TX_ACTIVE);
|
||||
}
|
||||
|
||||
static void reset_slave(void)
|
||||
{
|
||||
gpio_pin_t reset_pin = { 0 };
|
||||
if (ESP_TRANSPORT_OK != esp_hosted_transport_get_reset_config(&reset_pin)) {
|
||||
ESP_LOGE(TAG, "Unable to get RESET config for transport");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Reset slave using GPIO[%u]", reset_pin.pin);
|
||||
g_h.funcs->_h_config_gpio(H_GPIO_PIN_RESET_Port, reset_pin.pin, H_GPIO_MODE_DEF_OUTPUT);
|
||||
|
||||
g_h.funcs->_h_write_gpio(reset_pin.port, reset_pin.pin, H_RESET_VAL_ACTIVE);
|
||||
g_h.funcs->_h_msleep(50);
|
||||
g_h.funcs->_h_write_gpio(reset_pin.port, reset_pin.pin, H_RESET_VAL_INACTIVE);
|
||||
g_h.funcs->_h_msleep(50);
|
||||
g_h.funcs->_h_write_gpio(reset_pin.port, reset_pin.pin, H_RESET_VAL_ACTIVE);
|
||||
|
||||
/* stop spi transactions short time to avoid slave sync issues */
|
||||
g_h.funcs->_h_msleep(1500);
|
||||
}
|
||||
|
||||
static void transport_driver_event_handler(uint8_t event)
|
||||
{
|
||||
switch(event)
|
||||
{
|
||||
case TRANSPORT_TX_ACTIVE:
|
||||
{
|
||||
/* Initiate control path now */
|
||||
ESP_LOGI(TAG, "Base transport is set-up\n\r");
|
||||
if (transport_esp_hosted_up_cb)
|
||||
transport_esp_hosted_up_cb();
|
||||
transport_state = TRANSPORT_TX_ACTIVE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t transport_drv_deinit(void)
|
||||
{
|
||||
transport_deinit_internal();
|
||||
transport_state = TRANSPORT_INACTIVE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t transport_drv_init(void(*esp_hosted_up_cb)(void))
|
||||
{
|
||||
g_h.funcs->_h_hosted_init_hook();
|
||||
transport_init_internal();
|
||||
hci_drv_init();
|
||||
transport_esp_hosted_up_cb = esp_hosted_up_cb;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t transport_drv_reconfigure(void)
|
||||
{
|
||||
static int retry_slave_connection = 0;
|
||||
|
||||
ESP_LOGI(TAG, "Attempt connection with slave: retry[%u]",retry_slave_connection);
|
||||
if (!is_transport_tx_ready()) {
|
||||
reset_slave();
|
||||
transport_state = TRANSPORT_RX_ACTIVE;
|
||||
|
||||
while (!is_transport_tx_ready()) {
|
||||
if (retry_slave_connection < MAX_RETRY_TRANSPORT_ACTIVE) {
|
||||
retry_slave_connection++;
|
||||
if (retry_slave_connection%10==0) {
|
||||
ESP_LOGE(TAG, "Not able to connect with ESP-Hosted slave device");
|
||||
reset_slave();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to get ESP_Hosted slave transport up");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
g_h.funcs->_h_sleep(1);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Transport is already up");
|
||||
}
|
||||
retry_slave_connection = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t transport_drv_remove_channel(transport_channel_t *channel)
|
||||
{
|
||||
if (!channel)
|
||||
return ESP_FAIL;
|
||||
|
||||
switch (channel->if_type) {
|
||||
case ESP_AP_IF:
|
||||
case ESP_STA_IF:
|
||||
//Should we additionally do:
|
||||
//esp_wifi_internal_reg_rxcb(channel->if_type, NULL);
|
||||
break;
|
||||
case ESP_SERIAL_IF:
|
||||
/* TODO */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(chan_arr[channel->if_type] == channel);
|
||||
|
||||
mempool_destroy(channel->memp);
|
||||
chan_arr[channel->if_type] = NULL;
|
||||
HOSTED_FREE(channel);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
esp_err_t transport_drv_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
if (!h) {
|
||||
esp_wifi_internal_free_rx_buffer(buffer);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Buffer will be freed always in the called function */
|
||||
return esp_hosted_tx(h->if_type, 0, buffer, len, H_BUFF_NO_ZEROCOPY, esp_wifi_internal_free_rx_buffer);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static esp_err_t transport_drv_sta_tx(void *h, void *buffer, transport_free_cb_t free_cb, size_t len)
|
||||
{
|
||||
ESP_LOGI(TAG, "%s", __func__);
|
||||
assert(h && h==chan_arr[ESP_STA_IF]->api_chan);
|
||||
return esp_hosted_tx(ESP_STA_IF, 0, buffer, len, H_BUFF_NO_ZEROCOPY, free_cb);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void transport_sta_free_cb(void *buf)
|
||||
{
|
||||
mempool_free(chan_arr[ESP_STA_IF]->memp, buf);
|
||||
}
|
||||
|
||||
static void transport_ap_free_cb(void *buf)
|
||||
{
|
||||
mempool_free(chan_arr[ESP_AP_IF]->memp, buf);
|
||||
}
|
||||
|
||||
static void transport_serial_free_cb(void *buf)
|
||||
{
|
||||
mempool_free(chan_arr[ESP_SERIAL_IF]->memp, buf);
|
||||
}
|
||||
|
||||
static esp_err_t transport_drv_sta_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
void * copy_buff = NULL;
|
||||
|
||||
if (!buffer || !len)
|
||||
return ESP_OK;
|
||||
|
||||
if (unlikely(wifi_tx_throttling)) {
|
||||
#if ESP_PKT_STATS
|
||||
pkt_stats.sta_tx_in_drop++;
|
||||
#endif
|
||||
errno = -ENOBUFS;
|
||||
//return ESP_ERR_NO_BUFFS;
|
||||
#if defined(ESP_ERR_ESP_NETIF_TX_FAILED)
|
||||
return ESP_ERR_ESP_NETIF_TX_FAILED;
|
||||
#else
|
||||
return ESP_ERR_ESP_NETIF_NO_MEM;
|
||||
#endif
|
||||
}
|
||||
|
||||
assert(h && h==chan_arr[ESP_STA_IF]->api_chan);
|
||||
|
||||
/* Prepare transport buffer directly consumable */
|
||||
copy_buff = mempool_alloc(((struct mempool*)chan_arr[ESP_STA_IF]->memp), MAX_TRANSPORT_BUFFER_SIZE, true);
|
||||
assert(copy_buff);
|
||||
g_h.funcs->_h_memcpy(copy_buff+H_ESP_PAYLOAD_HEADER_OFFSET, buffer, len);
|
||||
|
||||
return esp_hosted_tx(ESP_STA_IF, 0, copy_buff, len, H_BUFF_ZEROCOPY, transport_sta_free_cb);
|
||||
}
|
||||
|
||||
static esp_err_t transport_drv_ap_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
void * copy_buff = NULL;
|
||||
|
||||
if (!buffer || !len)
|
||||
return ESP_OK;
|
||||
|
||||
assert(h && h==chan_arr[ESP_AP_IF]->api_chan);
|
||||
|
||||
/* Prepare transport buffer directly consumable */
|
||||
copy_buff = mempool_alloc(((struct mempool*)chan_arr[ESP_AP_IF]->memp), MAX_TRANSPORT_BUFFER_SIZE, true);
|
||||
assert(copy_buff);
|
||||
g_h.funcs->_h_memcpy(copy_buff+H_ESP_PAYLOAD_HEADER_OFFSET, buffer, len);
|
||||
|
||||
return esp_hosted_tx(ESP_AP_IF, 0, copy_buff, len, H_BUFF_ZEROCOPY, transport_ap_free_cb);
|
||||
}
|
||||
|
||||
esp_err_t transport_drv_serial_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
/* TODO */
|
||||
assert(h && h==chan_arr[ESP_SERIAL_IF]->api_chan);
|
||||
return esp_hosted_tx(ESP_SERIAL_IF, 0, buffer, len, H_BUFF_NO_ZEROCOPY, transport_serial_free_cb);
|
||||
}
|
||||
|
||||
|
||||
transport_channel_t *transport_drv_add_channel(void *api_chan,
|
||||
esp_hosted_if_type_t if_type, uint8_t secure,
|
||||
transport_channel_tx_fn_t *tx, const transport_channel_rx_fn_t rx)
|
||||
{
|
||||
transport_channel_t *channel = NULL;
|
||||
|
||||
ESP_ERROR_CHECK(if_type >= ESP_MAX_IF);
|
||||
|
||||
if (!tx || !rx) {
|
||||
ESP_LOGE(TAG, "%s fail for IF[%u]: tx or rx is NULL", __func__, if_type );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (chan_arr[if_type]) {
|
||||
/* Channel config already existed */
|
||||
ESP_LOGW(TAG, "Channel [%u] already created, replace with new callbacks", if_type);
|
||||
HOSTED_FREE(chan_arr[if_type]);
|
||||
}
|
||||
|
||||
|
||||
chan_arr[if_type] = g_h.funcs->_h_calloc(sizeof(transport_channel_t), 1);
|
||||
assert(chan_arr[if_type]);
|
||||
channel = chan_arr[if_type];
|
||||
|
||||
switch (if_type) {
|
||||
|
||||
case ESP_STA_IF:
|
||||
*tx = transport_drv_sta_tx;
|
||||
break;
|
||||
|
||||
case ESP_AP_IF:
|
||||
*tx = transport_drv_ap_tx;
|
||||
break;
|
||||
|
||||
case ESP_SERIAL_IF:
|
||||
*tx = transport_drv_serial_tx;
|
||||
break;
|
||||
|
||||
default:
|
||||
//*tx = transport_drv_tx;
|
||||
ESP_LOGW(TAG, "Not yet suppported ESP_Hosted interface for if_type[%u]", if_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel->api_chan = api_chan;
|
||||
channel->if_type = if_type;
|
||||
channel->secure = secure;
|
||||
channel->tx = *tx;
|
||||
channel->rx = rx;
|
||||
|
||||
/* Need to change size wrt transport */
|
||||
channel->memp = mempool_create(MAX_TRANSPORT_BUFFER_SIZE);
|
||||
#ifdef H_USE_MEMPOOL
|
||||
assert(channel->memp);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Add ESP-Hosted channel IF[%u]: S[%u] Tx[%p] Rx[%p]",
|
||||
if_type, secure, *tx, rx);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
void process_capabilities(uint8_t cap)
|
||||
{
|
||||
ESP_LOGI(TAG, "capabilities: 0x%x",cap);
|
||||
}
|
||||
|
||||
static uint32_t process_ext_capabilities(uint8_t * ptr)
|
||||
{
|
||||
// ptr address may be not be 32-bit aligned
|
||||
uint32_t cap;
|
||||
|
||||
cap = (uint32_t)ptr[0] +
|
||||
((uint32_t)ptr[1] << 8) +
|
||||
((uint32_t)ptr[2] << 16) +
|
||||
((uint32_t)ptr[3] << 24);
|
||||
ESP_LOGI(TAG, "extended capabilities: 0x%"PRIx32,cap);
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
void process_priv_communication(interface_buffer_handle_t *buf_handle)
|
||||
{
|
||||
if (!buf_handle || !buf_handle->payload || !buf_handle->payload_len)
|
||||
return;
|
||||
|
||||
process_event(buf_handle->payload, buf_handle->payload_len);
|
||||
}
|
||||
|
||||
void print_capabilities(uint32_t cap)
|
||||
{
|
||||
ESP_LOGI(TAG, "Features supported are:");
|
||||
if (cap & ESP_WLAN_SDIO_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t * WLAN");
|
||||
if (cap & ESP_BT_UART_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t - HCI over UART");
|
||||
if (cap & ESP_BT_SDIO_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t - HCI over SDIO");
|
||||
if (cap & ESP_BT_SPI_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t - HCI over SPI");
|
||||
if ((cap & ESP_BLE_ONLY_SUPPORT) && (cap & ESP_BR_EDR_ONLY_SUPPORT))
|
||||
ESP_LOGI(TAG, "\t - BT/BLE dual mode");
|
||||
else if (cap & ESP_BLE_ONLY_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t - BLE only");
|
||||
else if (cap & ESP_BR_EDR_ONLY_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t - BR EDR only");
|
||||
}
|
||||
|
||||
static void print_ext_capabilities(uint8_t * ptr)
|
||||
{
|
||||
// ptr address may be not be 32-bit aligned
|
||||
uint32_t cap;
|
||||
|
||||
cap = (uint32_t)ptr[0] +
|
||||
((uint32_t)ptr[1] << 8) +
|
||||
((uint32_t)ptr[2] << 16) +
|
||||
((uint32_t)ptr[3] << 24);
|
||||
|
||||
ESP_LOGI(TAG, "Extended Features supported:");
|
||||
#if H_SPI_HD_HOST_INTERFACE
|
||||
if (cap & ESP_SPI_HD_INTERFACE_SUPPORT_2_DATA_LINES)
|
||||
ESP_LOGI(TAG, "\t * SPI HD 2 data lines interface");
|
||||
if (cap & ESP_SPI_HD_INTERFACE_SUPPORT_4_DATA_LINES)
|
||||
ESP_LOGI(TAG, "\t * SPI HD 4 data lines interface");
|
||||
if (cap & ESP_WLAN_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t * WLAN");
|
||||
if (cap & ESP_BT_INTERFACE_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t * BT/BLE");
|
||||
#elif H_UART_HOST_TRANSPORT
|
||||
if (cap & ESP_WLAN_UART_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t * WLAN over UART");
|
||||
if (cap & ESP_BT_VHCI_UART_SUPPORT)
|
||||
ESP_LOGI(TAG, "\t * BT over UART (VHCI)");
|
||||
#else
|
||||
ESP_LOGI(TAG, "\t No extended features. capabilities[%" PRIu32 "]", cap);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void process_event(uint8_t *evt_buf, uint16_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
struct esp_priv_event *event;
|
||||
|
||||
if (!evt_buf || !len)
|
||||
return;
|
||||
|
||||
event = (struct esp_priv_event *) evt_buf;
|
||||
|
||||
if (event->event_type == ESP_PRIV_EVENT_INIT) {
|
||||
|
||||
ESP_LOGI(TAG, "Received INIT event from ESP32 peripheral");
|
||||
ESP_HEXLOGD("Slave_init_evt", event->event_data, event->event_len);
|
||||
|
||||
ret = process_init_event(event->event_data, event->event_len);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "failed to init event\n\r");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Drop unknown event\n\r");
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t get_chip_str_from_id(int chip_id, char* chip_str)
|
||||
{
|
||||
int ret = ESP_OK;
|
||||
assert(chip_str);
|
||||
|
||||
switch(chip_id) {
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32:
|
||||
strcpy(chip_str, "esp32");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32C2:
|
||||
strcpy(chip_str, "esp32c2");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32C3:
|
||||
strcpy(chip_str, "esp32c3");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32C6:
|
||||
strcpy(chip_str, "esp32c6");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32S2:
|
||||
strcpy(chip_str, "esp32s2");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32S3:
|
||||
strcpy(chip_str, "esp32s3");
|
||||
break;
|
||||
case ESP_PRIV_FIRMWARE_CHIP_ESP32C5:
|
||||
strcpy(chip_str, "esp32c5");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported chip id: %u", chip_id);
|
||||
strcpy(chip_str, "unsupported");
|
||||
ret = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void verify_host_config_for_slave(uint8_t chip_type)
|
||||
{
|
||||
uint8_t exp_chip_id = 0xff;
|
||||
|
||||
|
||||
#if H_SLAVE_TARGET_ESP32
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32;
|
||||
#elif H_SLAVE_TARGET_ESP32C2
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32C2;
|
||||
#elif H_SLAVE_TARGET_ESP32C3
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32C3;
|
||||
#elif H_SLAVE_TARGET_ESP32C6
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32C6;
|
||||
#elif H_SLAVE_TARGET_ESP32S2
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32S2;
|
||||
#elif H_SLAVE_TARGET_ESP32S3
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32S3;
|
||||
#elif H_SLAVE_TARGET_ESP32C5
|
||||
exp_chip_id = ESP_PRIV_FIRMWARE_CHIP_ESP32C5;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Incorrect host config for ESP slave chipset[%x]", chip_type);
|
||||
#endif
|
||||
if (chip_type!=exp_chip_id) {
|
||||
char slave_str[20], exp_str[20];
|
||||
|
||||
memset(slave_str, '\0', 20);
|
||||
memset(exp_str, '\0', 20);
|
||||
|
||||
get_chip_str_from_id(chip_type, slave_str);
|
||||
get_chip_str_from_id(exp_chip_id, exp_str);
|
||||
ESP_LOGE(TAG, "Identified slave [%s] != Expected [%s]\n\t\trun 'idf.py menuconfig' at host to reselect the slave?\n\t\tAborting.. ", slave_str, exp_str);
|
||||
g_h.funcs->_h_sleep(10);
|
||||
assert(0!=0);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t send_slave_config(uint8_t host_cap, uint8_t firmware_chip_id,
|
||||
uint8_t raw_tp_direction, uint8_t low_thr_thesh, uint8_t high_thr_thesh)
|
||||
{
|
||||
#define LENGTH_1_BYTE 1
|
||||
struct esp_priv_event *event = NULL;
|
||||
uint8_t *pos = NULL;
|
||||
uint16_t len = 0;
|
||||
uint8_t *sendbuf = NULL;
|
||||
|
||||
sendbuf = g_h.funcs->_h_malloc(512);
|
||||
assert(sendbuf);
|
||||
|
||||
/* Populate event data */
|
||||
//event = (struct esp_priv_event *) (sendbuf + sizeof(struct esp_payload_header)); //ZeroCopy
|
||||
event = (struct esp_priv_event *) (sendbuf);
|
||||
|
||||
event->event_type = ESP_PRIV_EVENT_INIT;
|
||||
|
||||
/* Populate TLVs for event */
|
||||
pos = event->event_data;
|
||||
|
||||
/* TLVs start */
|
||||
|
||||
/* TLV - Board type */
|
||||
ESP_LOGI(TAG, "Slave chip Id[%x]", ESP_PRIV_FIRMWARE_CHIP_ID);
|
||||
*pos = HOST_CAPABILITIES; pos++;len++;
|
||||
*pos = LENGTH_1_BYTE; pos++;len++;
|
||||
*pos = host_cap; pos++;len++;
|
||||
|
||||
/* TLV - Capability */
|
||||
*pos = RCVD_ESP_FIRMWARE_CHIP_ID; pos++;len++;
|
||||
*pos = LENGTH_1_BYTE; pos++;len++;
|
||||
*pos = firmware_chip_id; pos++;len++;
|
||||
|
||||
*pos = SLV_CONFIG_TEST_RAW_TP; pos++;len++;
|
||||
*pos = LENGTH_1_BYTE; pos++;len++;
|
||||
*pos = raw_tp_direction; pos++;len++;
|
||||
|
||||
*pos = SLV_CONFIG_THROTTLE_HIGH_THRESHOLD; pos++;len++;
|
||||
*pos = LENGTH_1_BYTE; pos++;len++;
|
||||
*pos = high_thr_thesh; pos++;len++;
|
||||
|
||||
*pos = SLV_CONFIG_THROTTLE_LOW_THRESHOLD; pos++;len++;
|
||||
*pos = LENGTH_1_BYTE; pos++;len++;
|
||||
*pos = low_thr_thesh; pos++;len++;
|
||||
|
||||
/* TLVs end */
|
||||
|
||||
event->event_len = len;
|
||||
|
||||
/* payload len = Event len + sizeof(event type) + sizeof(event len) */
|
||||
len += 2;
|
||||
|
||||
return esp_hosted_tx(ESP_PRIV_IF, 0, sendbuf, len, H_BUFF_NO_ZEROCOPY, g_h.funcs->_h_free);
|
||||
}
|
||||
|
||||
int process_init_event(uint8_t *evt_buf, uint16_t len)
|
||||
{
|
||||
uint8_t len_left = len, tag_len;
|
||||
uint8_t *pos;
|
||||
uint8_t raw_tp_config = H_TEST_RAW_TP_DIR;
|
||||
uint32_t ext_cap = 0;
|
||||
|
||||
if (!evt_buf)
|
||||
return ESP_FAIL;
|
||||
|
||||
pos = evt_buf;
|
||||
ESP_LOGD(TAG, "Init event length: %u", len);
|
||||
if (len > 64) {
|
||||
ESP_LOGE(TAG, "Init event length: %u", len);
|
||||
#if H_TRANSPORT_IN_USE == H_TRANSPORT_SPI
|
||||
ESP_LOGE(TAG, "Seems incompatible SPI mode try changing SPI mode. Asserting for now.");
|
||||
#endif
|
||||
assert(len < 64);
|
||||
}
|
||||
|
||||
while (len_left) {
|
||||
tag_len = *(pos + 1);
|
||||
|
||||
if (*pos == ESP_PRIV_CAPABILITY) {
|
||||
ESP_LOGI(TAG, "EVENT: %2x", *pos);
|
||||
process_capabilities(*(pos + 2));
|
||||
print_capabilities(*(pos + 2));
|
||||
} else if (*pos == ESP_PRIV_CAP_EXT) {
|
||||
ESP_LOGI(TAG, "EVENT: %2x", *pos);
|
||||
ext_cap = process_ext_capabilities(pos + 2);
|
||||
print_ext_capabilities(pos + 2);
|
||||
} else if (*pos == ESP_PRIV_FIRMWARE_CHIP_ID) {
|
||||
ESP_LOGI(TAG, "EVENT: %2x", *pos);
|
||||
chip_type = *(pos+2);
|
||||
verify_host_config_for_slave(chip_type);
|
||||
} else if (*pos == ESP_PRIV_TEST_RAW_TP) {
|
||||
ESP_LOGI(TAG, "EVENT: %2x", *pos);
|
||||
#if TEST_RAW_TP
|
||||
process_test_capabilities(*(pos + 2));
|
||||
#else
|
||||
if (*(pos + 2))
|
||||
ESP_LOGW(TAG, "Slave enabled Raw Throughput Testing, but not enabled on Host");
|
||||
#endif
|
||||
} else if (*pos == ESP_PRIV_RX_Q_SIZE) {
|
||||
ESP_LOGD(TAG, "slave rx queue size: %u", *(pos + 2));
|
||||
} else if (*pos == ESP_PRIV_TX_Q_SIZE) {
|
||||
ESP_LOGD(TAG, "slave tx queue size: %u", *(pos + 2));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Unsupported EVENT: %2x", *pos);
|
||||
}
|
||||
pos += (tag_len+2);
|
||||
len_left -= (tag_len+2);
|
||||
}
|
||||
|
||||
if ((chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32S2) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32S3) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32C2) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32C3) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32C6) &&
|
||||
(chip_type != ESP_PRIV_FIRMWARE_CHIP_ESP32C5)) {
|
||||
ESP_LOGI(TAG, "ESP board type is not mentioned, ignoring [%d]\n\r", chip_type);
|
||||
chip_type = ESP_PRIV_FIRMWARE_CHIP_UNRECOGNIZED;
|
||||
return -1;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ESP board type is : %d \n\r", chip_type);
|
||||
}
|
||||
|
||||
if (ext_cap) {
|
||||
#if H_SPI_HD_HOST_INTERFACE
|
||||
// reconfigure SPI_HD interface based on host and slave capabilities
|
||||
if (H_SPI_HD_HOST_NUM_DATA_LINES == 4) {
|
||||
// SPI_HD on host is configured to use 4 data bits
|
||||
if (ext_cap & ESP_SPI_HD_INTERFACE_SUPPORT_4_DATA_LINES) {
|
||||
// slave configured to use 4 bits
|
||||
ESP_LOGI(TAG, "configure SPI_HD interface to use 4 data lines");
|
||||
g_h.funcs->_h_spi_hd_set_data_lines(H_SPI_HD_CONFIG_4_DATA_LINES);
|
||||
} else {
|
||||
// slave configured to use 2 bits
|
||||
ESP_LOGI(TAG, "configure SPI_HD interface to use 2 data lines");
|
||||
g_h.funcs->_h_spi_hd_set_data_lines(H_SPI_HD_CONFIG_2_DATA_LINES);
|
||||
}
|
||||
} else {
|
||||
// SPI_HD on host is configured to use 2 data bits
|
||||
if (ext_cap & ESP_SPI_HD_INTERFACE_SUPPORT_4_DATA_LINES) {
|
||||
// slave configured to use 4 bits
|
||||
ESP_LOGI(TAG, "SPI_HD on slave uses 4 data lines but Host is configure to use 2 data lines");
|
||||
g_h.funcs->_h_spi_hd_set_data_lines(H_SPI_HD_CONFIG_2_DATA_LINES);
|
||||
} else {
|
||||
// slave configured to use 2 bits
|
||||
ESP_LOGI(TAG, "configure SPI_HD interface to use 2 data lines");
|
||||
g_h.funcs->_h_spi_hd_set_data_lines(H_SPI_HD_CONFIG_2_DATA_LINES);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
transport_driver_event_handler(TRANSPORT_TX_ACTIVE);
|
||||
return send_slave_config(0, chip_type, raw_tp_config,
|
||||
H_WIFI_TX_DATA_THROTTLE_LOW_THRESHOLD,
|
||||
H_WIFI_TX_DATA_THROTTLE_HIGH_THRESHOLD);
|
||||
}
|
||||
|
||||
int serial_rx_handler(interface_buffer_handle_t * buf_handle)
|
||||
{
|
||||
return serial_ll_rx_handler(buf_handle);
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __TRANSPORT_DRV_H
|
||||
#define __TRANSPORT_DRV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Includes **/
|
||||
|
||||
#include "common.h"
|
||||
#if 0
|
||||
#include "os_wrapper.h"
|
||||
#include "trace.h"
|
||||
#endif
|
||||
//#include "netdev_if.h"
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "esp_hosted_config.h"
|
||||
#include "esp_hosted_api_types.h"
|
||||
#include "esp_hosted_interface.h"
|
||||
#include "esp_hosted_header.h"
|
||||
|
||||
/* ESP in sdkconfig has CONFIG_IDF_FIRMWARE_CHIP_ID entry.
|
||||
* supported values of CONFIG_IDF_FIRMWARE_CHIP_ID are - */
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_UNRECOGNIZED (0xff)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32 (0x0)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32S2 (0x2)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32C3 (0x5)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32S3 (0x9)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32C2 (0xC)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32C6 (0xD)
|
||||
#define ESP_PRIV_FIRMWARE_CHIP_ESP32C5 (0x17)
|
||||
|
||||
|
||||
#if H_TRANSPORT_IN_USE == H_TRANSPORT_SPI
|
||||
#include "spi_wrapper.h"
|
||||
#define SPI_MODE0 (0)
|
||||
#define SPI_MODE1 (1)
|
||||
#define SPI_MODE2 (2)
|
||||
#define SPI_MODE3 (3)
|
||||
#else
|
||||
#include "sdio_wrapper.h"
|
||||
#endif
|
||||
|
||||
struct esp_private {
|
||||
uint8_t if_type;
|
||||
uint8_t if_num;
|
||||
void *netdev;
|
||||
};
|
||||
|
||||
struct hosted_transport_context_t {
|
||||
uint8_t *tx_buf;
|
||||
uint32_t tx_buf_size;
|
||||
uint8_t *rx_buf;
|
||||
};
|
||||
|
||||
extern volatile uint8_t wifi_tx_throttling;
|
||||
|
||||
typedef int (*hosted_rxcb_t)(void *buffer, uint16_t len, void *free_buff_hdl);
|
||||
|
||||
typedef void (transport_free_cb_t)(void* buffer);
|
||||
typedef esp_err_t (*transport_channel_tx_fn_t)(void *h, void *buffer, size_t len);
|
||||
typedef esp_err_t (*transport_channel_rx_fn_t)(void *h, void *buffer, void * buff_to_free, size_t len);
|
||||
|
||||
typedef struct {
|
||||
void * api_chan;
|
||||
esp_hosted_if_type_t if_type;
|
||||
uint8_t secure;
|
||||
transport_channel_tx_fn_t tx;
|
||||
transport_channel_rx_fn_t rx;
|
||||
void *memp;
|
||||
} transport_channel_t;
|
||||
|
||||
#if 0
|
||||
/* netdev APIs*/
|
||||
int esp_netdev_open(netdev_handle_t netdev);
|
||||
int esp_netdev_close(netdev_handle_t netdev);
|
||||
int esp_netdev_xmit(netdev_handle_t netdev, struct pbuf *net_buf);
|
||||
#endif
|
||||
|
||||
|
||||
esp_err_t transport_drv_init(void(*esp_hosted_up_cb)(void));
|
||||
esp_err_t transport_drv_deinit(void);
|
||||
esp_err_t transport_drv_reconfigure(void);
|
||||
transport_channel_t *transport_drv_add_channel(void *api_chan,
|
||||
esp_hosted_if_type_t if_type, uint8_t secure,
|
||||
transport_channel_tx_fn_t *tx, const transport_channel_rx_fn_t rx);
|
||||
esp_err_t transport_drv_remove_channel(transport_channel_t *channel);
|
||||
|
||||
/* TODO To move to private header */
|
||||
void process_capabilities(uint8_t cap);
|
||||
void transport_init_internal(void);
|
||||
void transport_deinit_internal(void);
|
||||
|
||||
void process_priv_communication(interface_buffer_handle_t *buf_handle);
|
||||
void print_capabilities(uint32_t cap);
|
||||
int process_init_event(uint8_t *evt_buf, uint16_t len);
|
||||
esp_err_t send_slave_config(uint8_t host_cap, uint8_t firmware_chip_id,
|
||||
uint8_t raw_tp_direction, uint8_t low_thr_thesh, uint8_t high_thr_thesh);
|
||||
|
||||
uint8_t is_transport_rx_ready(void);
|
||||
uint8_t is_transport_tx_ready(void);
|
||||
|
||||
#define H_BUFF_NO_ZEROCOPY 0
|
||||
#define H_BUFF_ZEROCOPY 1
|
||||
|
||||
#define H_DEFLT_FREE_FUNC g_h.funcs->_h_free
|
||||
|
||||
#define MAX_RETRY_TRANSPORT_ACTIVE 1000
|
||||
|
||||
|
||||
int esp_hosted_tx(uint8_t iface_type, uint8_t iface_num,
|
||||
uint8_t * buffer, uint16_t len, uint8_t buff_zerocopy, void (*free_buf_fun)(void* ptr));
|
||||
|
||||
int esp_hosted_register_wifi_rxcb(int ifx, hosted_rxcb_t fn);
|
||||
int esp_hosted_register_wifi_txcb(int ifx, hosted_rxcb_t fn);
|
||||
|
||||
int serial_rx_handler(interface_buffer_handle_t * buf_handle);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,554 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 "drivers/bt/hci_drv.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "endian.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_hosted_log.h"
|
||||
#include "transport_drv.h"
|
||||
#include "stats.h"
|
||||
|
||||
static const char TAG[] = "H_UART_DRV";
|
||||
|
||||
// UART is low throughput, so throttling should not be needed
|
||||
#define USE_DATA_THROTTLING (0)
|
||||
|
||||
static void h_uart_write_task(void const* pvParameters);
|
||||
static void h_uart_read_task(void const* pvParameters);
|
||||
#if USE_DATA_THROTTLING
|
||||
static int update_flow_ctrl(uint8_t *rxbuff);
|
||||
#endif
|
||||
|
||||
/* TODO to move this in transport drv */
|
||||
extern transport_channel_t *chan_arr[ESP_MAX_IF];
|
||||
|
||||
static void * h_uart_write_task_info;
|
||||
static void * h_uart_read_task_info;
|
||||
static void * h_uart_process_rx_task_info;
|
||||
|
||||
static void * uart_handle = NULL;
|
||||
|
||||
static queue_handle_t to_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
static semaphore_handle_t sem_to_slave_queue;
|
||||
static queue_handle_t from_slave_queue[MAX_PRIORITY_QUEUES];
|
||||
static semaphore_handle_t sem_from_slave_queue;
|
||||
|
||||
// one-time trigger to start write thread
|
||||
static bool uart_start_write_thread = false;
|
||||
|
||||
/* Create mempool for cache mallocs */
|
||||
static struct mempool * buf_mp_g;
|
||||
|
||||
static inline void h_uart_mempool_create(void)
|
||||
{
|
||||
MEM_DUMP("h_uart_mempool_create");
|
||||
buf_mp_g = mempool_create(MAX_UART_BUFFER_SIZE);
|
||||
#ifdef H_USE_MEMPOOL
|
||||
assert(buf_mp_g);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void *h_uart_buffer_alloc(uint need_memset)
|
||||
{
|
||||
return mempool_alloc(buf_mp_g, MAX_UART_BUFFER_SIZE, need_memset);
|
||||
}
|
||||
|
||||
static inline void h_uart_buffer_free(void *buf)
|
||||
{
|
||||
mempool_free(buf_mp_g, buf);
|
||||
}
|
||||
|
||||
static void h_uart_write_task(void const* pvParameters)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
uint8_t *sendbuf = NULL;
|
||||
void (*free_func)(void* ptr) = NULL;
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
uint8_t * payload = NULL;
|
||||
struct esp_payload_header * payload_header = NULL;
|
||||
|
||||
uint8_t tx_needed = 1;
|
||||
|
||||
int tx_len_to_send;
|
||||
int tx_len;
|
||||
|
||||
while (!uart_start_write_thread)
|
||||
g_h.funcs->_h_msleep(10);
|
||||
|
||||
while (1) {
|
||||
/* Check if higher layers have anything to transmit */
|
||||
g_h.funcs->_h_get_semaphore(sem_to_slave_queue, HOSTED_BLOCK_MAX);
|
||||
|
||||
/* Tx msg is present as per sem */
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_SERIAL], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_BT], &buf_handle, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(to_slave_queue[PRIO_Q_OTHERS], &buf_handle, 0)) {
|
||||
tx_needed = 0; /* No Tx msg */
|
||||
}
|
||||
|
||||
if (tx_needed)
|
||||
len = buf_handle.payload_len;
|
||||
|
||||
if (!len) {
|
||||
ESP_LOGE(TAG, "%s: Empty len", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
sendbuf = h_uart_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(sendbuf);
|
||||
free_func = h_uart_buffer_free;
|
||||
} else {
|
||||
sendbuf = buf_handle.payload;
|
||||
free_func = buf_handle.free_buf_handle;
|
||||
}
|
||||
|
||||
if (!sendbuf) {
|
||||
ESP_LOGE(TAG, "uart buff malloc failed");
|
||||
free_func = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (buf_handle.payload_len > MAX_UART_BUFFER_SIZE - sizeof(struct esp_payload_header)) {
|
||||
ESP_LOGE(TAG, "Pkt len [%u] > Max [%u]. Drop",
|
||||
buf_handle.payload_len, MAX_UART_BUFFER_SIZE - sizeof(struct esp_payload_header));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Form Tx header */
|
||||
payload_header = (struct esp_payload_header *) sendbuf;
|
||||
payload = sendbuf + sizeof(struct esp_payload_header);
|
||||
|
||||
payload_header->len = htole16(len);
|
||||
payload_header->offset = htole16(sizeof(struct esp_payload_header));
|
||||
payload_header->if_type = buf_handle.if_type;
|
||||
payload_header->if_num = buf_handle.if_num;
|
||||
payload_header->seq_num = htole16(buf_handle.seq_num);
|
||||
payload_header->flags = buf_handle.flag;
|
||||
|
||||
if (payload_header->if_type == ESP_HCI_IF) {
|
||||
// special handling for HCI
|
||||
if (!buf_handle.payload_zcopy) {
|
||||
// copy first byte of payload into header
|
||||
payload_header->hci_pkt_type = buf_handle.payload[0];
|
||||
// adjust actual payload len
|
||||
len -= 1;
|
||||
payload_header->len = htole16(len);
|
||||
g_h.funcs->_h_memcpy(payload, &buf_handle.payload[1], len);
|
||||
}
|
||||
} else
|
||||
if (!buf_handle.payload_zcopy)
|
||||
g_h.funcs->_h_memcpy(payload, buf_handle.payload, len);
|
||||
|
||||
#if H_UART_CHECKSUM
|
||||
payload_header->checksum = htole16(compute_checksum(sendbuf,
|
||||
sizeof(struct esp_payload_header) + len));
|
||||
#endif
|
||||
|
||||
tx_len_to_send = len + sizeof(struct esp_payload_header);
|
||||
tx_len = g_h.funcs->_h_uart_write(uart_handle, sendbuf, tx_len_to_send);
|
||||
if (tx_len != tx_len_to_send) {
|
||||
ESP_LOGE(TAG, "failed to send uart data");
|
||||
}
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_out++;
|
||||
#endif
|
||||
|
||||
done:
|
||||
if (len && !buf_handle.payload_zcopy) {
|
||||
/* free allocated buffer, only if zerocopy is not requested */
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle.free_buf_handle, buf_handle.priv_buffer_handle);
|
||||
}
|
||||
H_FREE_PTR_WITH_FUNC(free_func, sendbuf);
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_DATA_THROTTLING
|
||||
static int update_flow_ctrl(uint8_t *rxbuff)
|
||||
{
|
||||
struct esp_payload_header * h = (struct esp_payload_header *)rxbuff;
|
||||
if (h->throttle_cmd) {
|
||||
if (h->throttle_cmd == H_FLOW_CTRL_ON) {
|
||||
wifi_tx_throttling = 1;
|
||||
}
|
||||
if (h->throttle_cmd == H_FLOW_CTRL_OFF) {
|
||||
wifi_tx_throttling = 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void h_uart_process_rx_task(void const* pvParameters)
|
||||
{
|
||||
interface_buffer_handle_t buf_handle_l = {0};
|
||||
interface_buffer_handle_t *buf_handle = NULL;
|
||||
int ret = 0;
|
||||
|
||||
struct esp_priv_event *event = NULL;
|
||||
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (is_transport_rx_ready()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
g_h.funcs->_h_get_semaphore(sem_from_slave_queue, HOSTED_BLOCK_MAX);
|
||||
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_SERIAL], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_BT], &buf_handle_l, 0))
|
||||
if (g_h.funcs->_h_dequeue_item(from_slave_queue[PRIO_Q_OTHERS], &buf_handle_l, 0)) {
|
||||
ESP_LOGI(TAG, "No element in any queue found");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf_handle = &buf_handle_l;
|
||||
|
||||
ESP_HEXLOGV("rx", buf_handle->payload, buf_handle->payload_len);
|
||||
|
||||
if (buf_handle->if_type == ESP_SERIAL_IF) {
|
||||
/* serial interface path */
|
||||
serial_rx_handler(buf_handle);
|
||||
} else if((buf_handle->if_type == ESP_STA_IF) ||
|
||||
(buf_handle->if_type == ESP_AP_IF)) {
|
||||
#if 1
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
/* TODO : Need to abstract heap_caps_malloc */
|
||||
uint8_t * copy_payload = (uint8_t *)g_h.funcs->_h_malloc(buf_handle->payload_len);
|
||||
assert(copy_payload);
|
||||
assert(buf_handle->payload_len);
|
||||
assert(buf_handle->payload);
|
||||
memcpy(copy_payload, buf_handle->payload, buf_handle->payload_len);
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle, buf_handle->priv_buffer_handle);
|
||||
|
||||
ret = chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
copy_payload, copy_payload, buf_handle->payload_len);
|
||||
if (unlikely(ret))
|
||||
HOSTED_FREE(copy_payload);
|
||||
}
|
||||
#else
|
||||
if (chan_arr[buf_handle->if_type] && chan_arr[buf_handle->if_type]->rx) {
|
||||
chan_arr[buf_handle->if_type]->rx(chan_arr[buf_handle->if_type]->api_chan,
|
||||
buf_handle->payload, NULL, buf_handle->payload_len);
|
||||
}
|
||||
#endif
|
||||
} else if (buf_handle->if_type == ESP_PRIV_IF) {
|
||||
process_priv_communication(buf_handle);
|
||||
hci_drv_show_configuration();
|
||||
/* priv transaction received */
|
||||
ESP_LOGI(TAG, "Received INIT event");
|
||||
uart_start_write_thread = true;
|
||||
|
||||
event = (struct esp_priv_event *) (buf_handle->payload);
|
||||
if (event->event_type != ESP_PRIV_EVENT_INIT) {
|
||||
/* User can re-use this type of transaction */
|
||||
}
|
||||
} else if (buf_handle->if_type == ESP_HCI_IF) {
|
||||
hci_rx_handler(buf_handle);
|
||||
} else if (buf_handle->if_type == ESP_TEST_IF) {
|
||||
#if TEST_RAW_TP
|
||||
update_test_raw_tp_rx_len(buf_handle->payload_len +
|
||||
H_ESP_PAYLOAD_HEADER_OFFSET);
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unknown type %d ", buf_handle->if_type);
|
||||
}
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_out++;
|
||||
#endif
|
||||
|
||||
/* Free buffer handle */
|
||||
/* When buffer offloaded to other module, that module is
|
||||
* responsible for freeing buffer. In case not offloaded or
|
||||
* failed to offload, buffer should be freed here.
|
||||
*/
|
||||
if (!buf_handle->payload_zcopy) {
|
||||
H_FREE_PTR_WITH_FUNC(buf_handle->free_buf_handle,
|
||||
buf_handle->priv_buffer_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pushes received packet data on to rx queue
|
||||
static esp_err_t push_to_rx_queue(uint8_t * rxbuff, uint16_t len, uint16_t offset)
|
||||
{
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
struct esp_payload_header *h= NULL;
|
||||
interface_buffer_handle_t buf_handle;
|
||||
|
||||
h = (struct esp_payload_header *)rxbuff;
|
||||
|
||||
memset(&buf_handle, 0, sizeof(interface_buffer_handle_t));
|
||||
|
||||
buf_handle.priv_buffer_handle = rxbuff;
|
||||
buf_handle.free_buf_handle = h_uart_buffer_free;
|
||||
buf_handle.payload_len = len;
|
||||
buf_handle.if_type = h->if_type;
|
||||
buf_handle.if_num = h->if_num;
|
||||
buf_handle.payload = rxbuff + offset;
|
||||
buf_handle.seq_num = le16toh(h->seq_num);
|
||||
buf_handle.flag = h->flags;
|
||||
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
/* else OTHERS by default */
|
||||
|
||||
g_h.funcs->_h_queue_item(from_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_from_slave_queue);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int is_valid_uart_rx_packet(uint8_t *rxbuff_a, uint16_t *len_a, uint16_t *offset_a)
|
||||
{
|
||||
struct esp_payload_header * h = (struct esp_payload_header *)rxbuff_a;
|
||||
uint16_t len = 0, offset = 0;
|
||||
#if H_UART_CHECKSUM
|
||||
uint16_t rx_checksum = 0, checksum = 0;
|
||||
#endif
|
||||
|
||||
if (!h || !len_a || !offset_a)
|
||||
return 0;
|
||||
|
||||
/* Fetch length and offset from payload header */
|
||||
len = le16toh(h->len);
|
||||
offset = le16toh(h->offset);
|
||||
|
||||
if ((!len) ||
|
||||
(len > MAX_PAYLOAD_SIZE) ||
|
||||
(offset != sizeof(struct esp_payload_header))) {
|
||||
|
||||
/* Free up buffer, as one of following -
|
||||
* 1. no payload to process
|
||||
* 2. input packet size > driver capacity
|
||||
* 3. payload header size mismatch,
|
||||
* wrong header/bit packing?
|
||||
* */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if H_UART_CHECKSUM
|
||||
rx_checksum = le16toh(h->checksum);
|
||||
h->checksum = 0;
|
||||
checksum = compute_checksum((uint8_t*)h, len + offset);
|
||||
|
||||
if (checksum != rx_checksum) {
|
||||
ESP_LOGE(TAG, "UART RX rx_chksum[%u] != checksum[%u]. Drop.",
|
||||
checksum, rx_checksum);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (h->if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_rx_in++;
|
||||
#endif
|
||||
|
||||
*len_a = len;
|
||||
*offset_a = offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t * uart_scratch_buf = NULL;
|
||||
|
||||
static void h_uart_read_task(void const* pvParameters)
|
||||
{
|
||||
struct esp_payload_header *header = NULL;
|
||||
uint16_t len = 0, offset = 0;
|
||||
#if HOSTED_UART_CHECKSUM
|
||||
uint16_t rx_checksum = 0, checksum = 0;
|
||||
#endif
|
||||
int bytes_read;
|
||||
int total_len;
|
||||
uint8_t * rxbuff = NULL;
|
||||
|
||||
// wait for transport to be in ready
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (is_transport_rx_ready()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
create_debugging_tasks();
|
||||
|
||||
if (!uart_scratch_buf) {
|
||||
uart_scratch_buf = malloc(MAX_UART_BUFFER_SIZE);
|
||||
assert(uart_scratch_buf);
|
||||
}
|
||||
|
||||
header = (struct esp_payload_header *)uart_scratch_buf;
|
||||
|
||||
while (1) {
|
||||
// get the header
|
||||
bytes_read = g_h.funcs->_h_uart_read(uart_handle, uart_scratch_buf,
|
||||
sizeof(struct esp_payload_header));
|
||||
ESP_LOGD(TAG, "Read %d bytes (header)", bytes_read);
|
||||
if (bytes_read < sizeof(struct esp_payload_header)) {
|
||||
ESP_LOGE(TAG, "Failed to read header");
|
||||
continue;
|
||||
}
|
||||
|
||||
len = le16toh(header->len);
|
||||
offset = le16toh(header->offset);
|
||||
total_len = len + sizeof(struct esp_payload_header);
|
||||
if (total_len > MAX_UART_BUFFER_SIZE) {
|
||||
ESP_LOGE(TAG, "incoming data too big: %d", total_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the data
|
||||
bytes_read = g_h.funcs->_h_uart_read(uart_handle, &uart_scratch_buf[offset], len);
|
||||
ESP_LOGD(TAG, "Read %d bytes (payload)", bytes_read);
|
||||
if (bytes_read < len) {
|
||||
ESP_LOGE(TAG, "Failed to read payload");
|
||||
continue;
|
||||
}
|
||||
|
||||
rxbuff = h_uart_buffer_alloc(MEMSET_REQUIRED);
|
||||
assert(rxbuff);
|
||||
|
||||
// copy data to the buffer
|
||||
memcpy(rxbuff, uart_scratch_buf, total_len);
|
||||
|
||||
#if USE_DATA_THROTTLING
|
||||
if (update_flow_ctrl(rxbuff)) {
|
||||
// detected and updated flow control
|
||||
// no need to further process the packet
|
||||
h_uart_buffer_free(rxbuff);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop packet if no processing needed */
|
||||
if (!is_valid_uart_rx_packet(rxbuff, &len, &offset)) {
|
||||
/* Free up buffer, as one of following -
|
||||
* 1. no payload to process
|
||||
* 2. input packet size > driver capacity
|
||||
* 3. payload header size mismatch,
|
||||
* wrong header/bit packing?
|
||||
* */
|
||||
ESP_LOGE(TAG, "Dropping packet");
|
||||
h_uart_buffer_free(rxbuff);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (push_to_rx_queue(rxbuff, len, offset)) {
|
||||
ESP_LOGE(TAG, "Failed to push Rx packet to queue");
|
||||
h_uart_buffer_free(rxbuff);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transport_init_internal(void)
|
||||
{
|
||||
uint8_t prio_q_idx = 0;
|
||||
|
||||
sem_to_slave_queue = g_h.funcs->_h_create_semaphore(H_UART_TX_QUEUE_SIZE*MAX_PRIORITY_QUEUES);
|
||||
assert(sem_to_slave_queue);
|
||||
g_h.funcs->_h_get_semaphore(sem_to_slave_queue, 0);
|
||||
|
||||
sem_from_slave_queue = g_h.funcs->_h_create_semaphore(H_UART_RX_QUEUE_SIZE*MAX_PRIORITY_QUEUES);
|
||||
assert(sem_from_slave_queue);
|
||||
g_h.funcs->_h_get_semaphore(sem_from_slave_queue, 0);
|
||||
|
||||
for (prio_q_idx=0; prio_q_idx<MAX_PRIORITY_QUEUES;prio_q_idx++) {
|
||||
/* Queue - rx */
|
||||
from_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(H_UART_RX_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(from_slave_queue[prio_q_idx]);
|
||||
|
||||
/* Queue - tx */
|
||||
to_slave_queue[prio_q_idx] = g_h.funcs->_h_create_queue(H_UART_TX_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
|
||||
assert(to_slave_queue[prio_q_idx]);
|
||||
}
|
||||
|
||||
h_uart_mempool_create();
|
||||
|
||||
uart_handle = g_h.funcs->_h_bus_init();
|
||||
if (!uart_handle) {
|
||||
ESP_LOGE(TAG, "could not create uart handle, exiting\n");
|
||||
assert(uart_handle);
|
||||
}
|
||||
|
||||
h_uart_process_rx_task_info = g_h.funcs->_h_thread_create("uart_process_rx",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, h_uart_process_rx_task, NULL);
|
||||
|
||||
h_uart_read_task_info = g_h.funcs->_h_thread_create("uart_rx",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, h_uart_read_task, NULL);
|
||||
|
||||
h_uart_write_task_info = g_h.funcs->_h_thread_create("uart_tx",
|
||||
DFLT_TASK_PRIO, DFLT_TASK_STACK_SIZE, h_uart_write_task, NULL);
|
||||
}
|
||||
|
||||
int esp_hosted_tx(uint8_t iface_type, uint8_t iface_num,
|
||||
uint8_t * wbuffer, uint16_t wlen, uint8_t buff_zcopy,
|
||||
void (*free_wbuf_fun)(void* ptr))
|
||||
{
|
||||
interface_buffer_handle_t buf_handle = {0};
|
||||
void (*free_func)(void* ptr) = NULL;
|
||||
uint8_t pkt_prio = PRIO_Q_OTHERS;
|
||||
uint8_t transport_up = is_transport_tx_ready();
|
||||
|
||||
if (free_wbuf_fun)
|
||||
free_func = free_wbuf_fun;
|
||||
|
||||
if (!wbuffer || !wlen ||
|
||||
(wlen > MAX_PAYLOAD_SIZE) ||
|
||||
!transport_up) {
|
||||
ESP_LOGE(TAG, "tx fail: NULL buff, invalid len (%u) or len > max len (%u), transport_up(%u))",
|
||||
wlen, MAX_PAYLOAD_SIZE, transport_up);
|
||||
H_FREE_PTR_WITH_FUNC(free_func, wbuffer);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
buf_handle.payload_zcopy = buff_zcopy;
|
||||
buf_handle.if_type = iface_type;
|
||||
buf_handle.if_num = iface_num;
|
||||
buf_handle.payload_len = wlen;
|
||||
buf_handle.payload = wbuffer;
|
||||
buf_handle.priv_buffer_handle = wbuffer;
|
||||
buf_handle.free_buf_handle = free_func;
|
||||
|
||||
if (buf_handle.if_type == ESP_SERIAL_IF)
|
||||
pkt_prio = PRIO_Q_SERIAL;
|
||||
else if (buf_handle.if_type == ESP_HCI_IF)
|
||||
pkt_prio = PRIO_Q_BT;
|
||||
|
||||
g_h.funcs->_h_queue_item(to_slave_queue[pkt_prio], &buf_handle, HOSTED_BLOCK_MAX);
|
||||
g_h.funcs->_h_post_semaphore(sem_to_slave_queue);
|
||||
|
||||
#if ESP_PKT_STATS
|
||||
if (buf_handle.if_type == ESP_STA_IF)
|
||||
pkt_stats.sta_tx_in_pass++;
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0 */
|
||||
|
||||
/** Includes **/
|
||||
#include <string.h>
|
||||
#include "os_wrapper.h"
|
||||
#include "serial_if.h"
|
||||
#include "serial_drv.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
DEFINE_LOG_TAG(serial_if);
|
||||
|
||||
/** Constants/Macros **/
|
||||
#define SUCCESS 0
|
||||
#define FAILURE -1
|
||||
|
||||
|
||||
#define PROTO_PSER_TLV_T_EPNAME 0x01
|
||||
#define PROTO_PSER_TLV_T_DATA 0x02
|
||||
|
||||
#if 0
|
||||
#ifdef MCU_SYS
|
||||
#define command_log(format, ...) printf(format "\r", ##__VA_ARGS__);
|
||||
#else
|
||||
#define command_log(...) printf("%s:%u ",__func__,__LINE__); \
|
||||
printf(__VA_ARGS__);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define HOSTED_CALLOC(buff,nbytes) do { \
|
||||
buff = (uint8_t *)g_h.funcs->_h_calloc(1, nbytes); \
|
||||
if (!buff) { \
|
||||
printf("%s, Failed to allocate memory \n", __func__); \
|
||||
goto free_bufs; \
|
||||
} \
|
||||
} while(0);
|
||||
#endif
|
||||
|
||||
/** Exported variables **/
|
||||
struct serial_drv_handle_t* serial_handle = NULL;
|
||||
|
||||
/*
|
||||
* The data written on serial driver file, `SERIAL_IF_FILE` from esp_hosted_transport.h
|
||||
* In TLV i.e. Type Length Value format, to transfer data between host and ESP32
|
||||
* | type | length | value |
|
||||
* Types are 0x01 : for endpoint name
|
||||
* 0x02 : for data
|
||||
* length is respective value field's data length in 16 bits
|
||||
* value is actual data to be transferred
|
||||
*/
|
||||
|
||||
uint16_t compose_tlv(uint8_t* buf, uint8_t* data, uint16_t data_length)
|
||||
{
|
||||
char* ep_name = RPC_EP_NAME_RSP;
|
||||
uint16_t ep_length = strlen(ep_name);
|
||||
uint16_t count = 0;
|
||||
uint8_t idx;
|
||||
|
||||
buf[count] = PROTO_PSER_TLV_T_EPNAME;
|
||||
count++;
|
||||
buf[count] = (ep_length & 0xFF);
|
||||
count++;
|
||||
buf[count] = ((ep_length >> 8) & 0xFF);
|
||||
count++;
|
||||
|
||||
for (idx = 0; idx < ep_length; idx++) {
|
||||
buf[count] = ep_name[idx];
|
||||
count++;
|
||||
}
|
||||
|
||||
buf[count]= PROTO_PSER_TLV_T_DATA;
|
||||
count++;
|
||||
buf[count] = (data_length & 0xFF);
|
||||
count++;
|
||||
buf[count] = ((data_length >> 8) & 0xFF);
|
||||
count++;
|
||||
g_h.funcs->_h_memcpy(&buf[count], data, data_length);
|
||||
count = count + data_length;
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t parse_tlv(uint8_t* data, uint32_t* pro_len)
|
||||
{
|
||||
char* ep_name = RPC_EP_NAME_RSP;
|
||||
char* ep_name2 = RPC_EP_NAME_EVT;
|
||||
uint64_t len = 0;
|
||||
uint16_t val_len = 0;
|
||||
if (data[len] == PROTO_PSER_TLV_T_EPNAME) {
|
||||
len++;
|
||||
val_len = data[len];
|
||||
len++;
|
||||
val_len = (data[len] << 8) + val_len;
|
||||
len++;
|
||||
/* Both RPC_EP_NAME_RSP and RPC_EP_NAME_EvT
|
||||
* are expected to have exactly same length
|
||||
**/
|
||||
if (val_len == strlen(ep_name)) {
|
||||
if ((strncmp((char* )&data[len],ep_name,strlen(ep_name)) == 0) ||
|
||||
(strncmp((char* )&data[len],ep_name2,strlen(ep_name2)) == 0)) {
|
||||
len = len + strlen(ep_name);
|
||||
if (data[len] == PROTO_PSER_TLV_T_DATA) {
|
||||
len++;
|
||||
val_len = data[len];
|
||||
len++;
|
||||
val_len = (data[len] << 8) + val_len;
|
||||
len++;
|
||||
*pro_len = val_len;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Data Type not matched, exp %d, recvd %d\n",
|
||||
PROTO_PSER_TLV_T_DATA, data[len]);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Endpoint Name not matched, exp [%s] or [%s], recvd [%s]\n",
|
||||
ep_name, ep_name2, (char* )&data[len]);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Endpoint length not matched, exp [For %s, %lu OR For %s, %lu], recvd %d\n",
|
||||
ep_name, (long unsigned int)(strlen(ep_name)),
|
||||
ep_name2, (long unsigned int)(strlen(ep_name2)), val_len);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Endpoint type not matched, exp %d, recvd %d\n",
|
||||
PROTO_PSER_TLV_T_EPNAME, data[len]);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int transport_pserial_close(void)
|
||||
{
|
||||
int ret = serial_drv_close(&serial_handle);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Failed to close driver interface\n");
|
||||
return FAILURE;
|
||||
}
|
||||
serial_handle = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int transport_pserial_open(void)
|
||||
{
|
||||
int ret = SUCCESS;
|
||||
const char* transport = SERIAL_IF_FILE;
|
||||
|
||||
if (serial_handle) {
|
||||
printf("Already opened returned\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial_handle = serial_drv_open(transport);
|
||||
if (!serial_handle) {
|
||||
printf("serial interface open failed, Is the driver loaded?\n");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ret = rpc_platform_init();
|
||||
if (ret != SUCCESS) {
|
||||
printf("Platform init failed\n");
|
||||
transport_pserial_close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int transport_pserial_send(uint8_t* data, uint16_t data_length)
|
||||
{
|
||||
char* ep_name = RPC_EP_NAME_RSP;
|
||||
int count = 0, ret = 0;
|
||||
uint16_t buf_len = 0;
|
||||
uint8_t *write_buf = NULL;
|
||||
|
||||
/*
|
||||
* TLV (Type - Length - Value) structure is as follows:
|
||||
* --------------------------------------------------------------------------------------------
|
||||
* Endpoint Type | Endpoint Length | Endpoint Value | Data Type | Data Length | Data Value |
|
||||
* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Bytes used per field as follows:
|
||||
* --------------------------------------------------------------------------------------------
|
||||
* 1 | 2 | Endpoint length | 1 | 2 | Data length |
|
||||
* --------------------------------------------------------------------------------------------
|
||||
*/
|
||||
buf_len = SIZE_OF_TYPE + SIZE_OF_LENGTH + strlen(ep_name) +
|
||||
SIZE_OF_TYPE + SIZE_OF_LENGTH + data_length;
|
||||
|
||||
HOSTED_CALLOC(uint8_t,write_buf,buf_len,free_bufs);
|
||||
|
||||
if (!serial_handle) {
|
||||
ESP_LOGE(TAG, "Serial connection closed?\n");
|
||||
goto free_bufs;
|
||||
}
|
||||
|
||||
count = compose_tlv(write_buf, data, data_length);
|
||||
if (!count) {
|
||||
ESP_LOGE(TAG, "Failed to compose TX data\n");
|
||||
goto free_bufs;
|
||||
}
|
||||
|
||||
ret = serial_drv_write(serial_handle, write_buf, count, &count);
|
||||
if (ret != SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to write TX data\n");
|
||||
goto free_bufs;
|
||||
}
|
||||
return SUCCESS;
|
||||
free_bufs:
|
||||
if (write_buf) {
|
||||
g_h.funcs->_h_free(write_buf);
|
||||
}
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
uint8_t * transport_pserial_read(uint32_t *out_nbyte)
|
||||
{
|
||||
/* Two step parsing TLV is moved in serial_drv_read */
|
||||
return serial_drv_read(serial_handle, out_nbyte);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015-2022 Espressif Systems (Shanghai) PTE LTD
|
||||
/* SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0 */
|
||||
|
||||
/** prevent recursive inclusion **/
|
||||
#ifndef __SERIAL_IF_H
|
||||
#define __SERIAL_IF_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_hosted_transport.h"
|
||||
#include "os_wrapper.h"
|
||||
|
||||
#define SIZE_OF_TYPE 1
|
||||
#define SIZE_OF_LENGTH 2
|
||||
|
||||
/*
|
||||
* The data written on serial driver file, `SERIAL_IF_FILE` from esp_hosted_transport.h
|
||||
* In TLV i.e. Type Length Value format, to transfer data between host and ESP32
|
||||
* | type | length | value |
|
||||
* Types are 0x01 : for endpoint name
|
||||
* 0x02 : for data
|
||||
* length is respective value field's data length in 16 bits
|
||||
* value is actual data to be transferred
|
||||
*/
|
||||
uint16_t compose_tlv(uint8_t* buf, uint8_t* data, uint16_t data_length);
|
||||
|
||||
/* Parse the protobuf encoded data in format of tag, length and value
|
||||
* Thi will help application to decode protobuf payload and payload length
|
||||
**/
|
||||
uint8_t parse_tlv(uint8_t* data, uint32_t* pro_len);
|
||||
|
||||
/* Open the serial driver for serial operations
|
||||
**/
|
||||
int transport_pserial_open(void);
|
||||
|
||||
/* Close the serial driver for serial operations
|
||||
**/
|
||||
int transport_pserial_close(void);
|
||||
|
||||
/* Send buffer with length as argument on transport as serial interface type
|
||||
**/
|
||||
int transport_pserial_send(uint8_t* data, uint16_t data_length);
|
||||
|
||||
/* Read and return number of bytes and buffer from serial interface
|
||||
**/
|
||||
uint8_t * transport_pserial_read(uint32_t *out_nbyte);
|
||||
#endif
|
||||
Reference in New Issue
Block a user