This commit is contained in:
iranl
2025-06-25 22:52:12 +02:00
parent 5fe5614686
commit 6c74d62531
519 changed files with 191600 additions and 5 deletions

View 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);
}
}

View 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

View File

@@ -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;
}

View File

@@ -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 */