P4 fixes
This commit is contained in:
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 */
|
||||
Reference in New Issue
Block a user