2025-10-10 16:07:00 +08:00

974 lines
22 KiB
C
Executable File

// Copyright 2020-2022 Beken
//
// 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 <stdio.h>
#include <string.h>
#include <os/os.h>
#include <driver/mailbox_channel.h>
#include <driver/mb_chnl_buff.h>
#include <driver/mb_uart_driver.h>
#if CONFIG_CACHE_ENABLE
#include "cache.h"
#endif
#define MOD_TAG "mUart"
// #define MB_UART_CRC8_ENABLE
#if (CONFIG_CPU_CNT > 1)
#define UART_XCHG_DATA_MAX MB_CHNL_BUFF_LEN
typedef union
{
struct
{
mb_chnl_hdr_t chnl_hdr;
void * cmd_buff;
u16 cmd_data_len;
u8 uart_rts : 1;
u8 resvd : 7;
u8 crc8;
};
mb_chnl_cmd_t mb_cmd;
} mb_uart_cmd_t;
typedef union
{
struct
{
mb_chnl_hdr_t chnl_hdr;
u8 uart_rts : 1;
u8 uart_tx_fail : 1;
u8 resvd : 6;
};
mb_chnl_ack_t mb_ack;
} mb_uart_rsp_t;
enum
{
MB_UART_SEND_DATA = 0,
MB_UART_SEND_STATE,
MB_UART_ASSERT_DATA,
MB_UART_CMD_MAX,
};
#define MB_UART_TX_FIFO_LEN UART_XCHG_DATA_MAX
#define MB_UART_RX_FIFO_LEN UART_XCHG_DATA_MAX
typedef struct
{
/* chnl data */
u8 chnl_inited;
u8 chnl_id;
/* uart CSR */
u8 ctrl_rts : 1; /* low level Asserted. */
u8 ctrl_resvd : 7;
u8 status_cts : 1; /* low level Asserted. */
u8 status_overflow : 1; /* NOT used, will discard RX data when error. */
u8 status_parity : 1; /* NOT used, will discard RX data when error. */
u8 status_frm_err : 1; /* NOT used, will discard RX data when error. */
u8 status_resvd : 4;
/* uart data */
mb_uart_isr_t rx_isr_callback;
mb_uart_isr_t tx_isr_callback;
void * rx_isr_param;
void * tx_isr_param;
/* tx channel */
u8 * tx_xchg_buff; /* uart tx FIFO */
u8 tx_buf[MB_UART_TX_FIFO_LEN];
u16 tx_rd_idx;
u16 tx_wr_idx;
volatile u16 tx_data_cnt;
volatile u8 tx_in_process;
u8 tx_cmd;
/* rx channel */
u8 * rx_xchg_buff; /* uart rx FIFO */
u8 rx_buf[2 * MB_UART_RX_FIFO_LEN];
u16 rx_rd_idx;
u16 rx_wr_idx;
volatile u16 rx_data_cnt;
} mb_uart_cb_t;
#ifdef MB_UART_CRC8_ENABLE
static const u8 crc8_table[] =
{
0x00,0x31,0x62,0x53,0xc4,0xf5,0xa6,0x97,0xb9,0x88,0xdb,0xea,0x7d,0x4c,0x1f,0x2e,
0x43,0x72,0x21,0x10,0x87,0xb6,0xe5,0xd4,0xfa,0xcb,0x98,0xa9,0x3e,0x0f,0x5c,0x6d,
0x86,0xb7,0xe4,0xd5,0x42,0x73,0x20,0x11,0x3f,0x0e,0x5d,0x6c,0xfb,0xca,0x99,0xa8,
0xc5,0xf4,0xa7,0x96,0x01,0x30,0x63,0x52,0x7c,0x4d,0x1e,0x2f,0xb8,0x89,0xda,0xeb,
0x3d,0x0c,0x5f,0x6e,0xf9,0xc8,0x9b,0xaa,0x84,0xb5,0xe6,0xd7,0x40,0x71,0x22,0x13,
0x7e,0x4f,0x1c,0x2d,0xba,0x8b,0xd8,0xe9,0xc7,0xf6,0xa5,0x94,0x03,0x32,0x61,0x50,
0xbb,0x8a,0xd9,0xe8,0x7f,0x4e,0x1d,0x2c,0x02,0x33,0x60,0x51,0xc6,0xf7,0xa4,0x95,
0xf8,0xc9,0x9a,0xab,0x3c,0x0d,0x5e,0x6f,0x41,0x70,0x23,0x12,0x85,0xb4,0xe7,0xd6,
0x7a,0x4b,0x18,0x29,0xbe,0x8f,0xdc,0xed,0xc3,0xf2,0xa1,0x90,0x07,0x36,0x65,0x54,
0x39,0x08,0x5b,0x6a,0xfd,0xcc,0x9f,0xae,0x80,0xb1,0xe2,0xd3,0x44,0x75,0x26,0x17,
0xfc,0xcd,0x9e,0xaf,0x38,0x09,0x5a,0x6b,0x45,0x74,0x27,0x16,0x81,0xb0,0xe3,0xd2,
0xbf,0x8e,0xdd,0xec,0x7b,0x4a,0x19,0x28,0x06,0x37,0x64,0x55,0xc2,0xf3,0xa0,0x91,
0x47,0x76,0x25,0x14,0x83,0xb2,0xe1,0xd0,0xfe,0xcf,0x9c,0xad,0x3a,0x0b,0x58,0x69,
0x04,0x35,0x66,0x57,0xc0,0xf1,0xa2,0x93,0xbd,0x8c,0xdf,0xee,0x79,0x48,0x1b,0x2a,
0xc1,0xf0,0xa3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1a,0x2b,0xbc,0x8d,0xde,0xef,
0x82,0xb3,0xe0,0xd1,0x46,0x77,0x24,0x15,0x3b,0x0a,0x59,0x68,0xff,0xce,0x9d,0xac
};
#endif
static u8 cal_crc8_0x31(u8 *data_buf, u16 len)
{
u8 crc = 0x00;
#if MB_UART_CRC8_ENABLE
for (u16 i = 0; i < len; i++)
{
crc = crc8_table[crc ^ data_buf[i]];
}
#endif
return (crc);
}
static bk_err_t mb_uart_send_data(mb_uart_cb_t *chnl_cb);
static void rx_isr_data_handler(mb_uart_cb_t *chnl_cb, mb_uart_cmd_t * uart_cmd)
{
/* overwrite the uart_cmd after the ISR handle completed.
* return the rsp info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
mb_uart_rsp_t * uart_rsp = (mb_uart_rsp_t *)uart_cmd;
u8 tx_fail = 0;
u8 old_cts = chnl_cb->status_cts;
/* chnl_cb->rx_xchg_buff == uart_cmd->cmd_buff. MUST be true. */
chnl_cb->status_cts = uart_cmd->uart_rts;
if((uart_cmd->cmd_buff == NULL) || (uart_cmd->cmd_data_len == 0))
{
goto rx_isr_data_xit;
}
else if((uart_cmd->cmd_data_len + chnl_cb->rx_data_cnt) > sizeof(chnl_cb->rx_buf))
{
chnl_cb->status_overflow = 1; /* discards all rx-data. */
tx_fail = 1;
}
else
{
#if CONFIG_CACHE_ENABLE
flush_dcache(uart_cmd->cmd_buff, uart_cmd->cmd_data_len);
#endif
u16 rem_len, cpy_len;
cpy_len = uart_cmd->cmd_data_len;
if(uart_cmd->crc8 != cal_crc8_0x31((u8 *)uart_cmd->cmd_buff, cpy_len))
{
chnl_cb->status_parity = 1; /* discards all rx-data. */
tx_fail = 1;
goto rx_isr_data_xit;
}
if(chnl_cb->rx_wr_idx < chnl_cb->rx_rd_idx)
{
memcpy(chnl_cb->rx_buf + chnl_cb->rx_wr_idx, uart_cmd->cmd_buff, cpy_len);
chnl_cb->rx_wr_idx += cpy_len;
}
else
{
rem_len = sizeof(chnl_cb->rx_buf) - chnl_cb->rx_wr_idx;
if(rem_len > cpy_len)
{
memcpy(chnl_cb->rx_buf + chnl_cb->rx_wr_idx, uart_cmd->cmd_buff, cpy_len);
chnl_cb->rx_wr_idx += cpy_len;
}
else
{
memcpy(chnl_cb->rx_buf + chnl_cb->rx_wr_idx, uart_cmd->cmd_buff, rem_len);
chnl_cb->rx_wr_idx = 0;
if(rem_len < cpy_len)
{
memcpy(chnl_cb->rx_buf, uart_cmd->cmd_buff + rem_len, cpy_len - rem_len);
}
chnl_cb->rx_wr_idx = cpy_len - rem_len;
}
}
chnl_cb->rx_data_cnt += cpy_len;
if(chnl_cb->rx_isr_callback != NULL)
{
chnl_cb->rx_isr_callback(chnl_cb->rx_isr_param);
}
}
rx_isr_data_xit:
if(chnl_cb->rx_data_cnt >= (sizeof(chnl_cb->rx_buf) - MB_UART_RX_FIFO_LEN))
{
chnl_cb->ctrl_rts = 1;
}
/* overwrite the uart_cmd after the ISR handle completed.
* return the rsp info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
uart_rsp->uart_rts = chnl_cb->ctrl_rts;
uart_rsp->uart_tx_fail = tx_fail;
uart_rsp->resvd = 0;
if(chnl_cb->status_cts != old_cts)
{
if(chnl_cb->status_cts == 0)
{
/* trigger send! */
mb_uart_send_data(chnl_cb);
}
}
return;
}
static void rx_isr_state_handler(mb_uart_cb_t *chnl_cb, mb_uart_cmd_t *uart_cmd)
{
/* overwrite the uart_cmd after the ISR handle completed.
* return the rsp info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
mb_uart_rsp_t * uart_rsp = (mb_uart_rsp_t *)uart_cmd;
u8 old_cts = chnl_cb->status_cts;
/* chnl_cb->rx_xchg_buff == uart_cmd->cmd_buff. MUST be true. */
chnl_cb->status_cts = uart_cmd->uart_rts;
/* overwrite the uart_cmd after the ISR handle completed.
* return the rsp info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
uart_rsp->uart_rts = chnl_cb->ctrl_rts;
uart_rsp->uart_tx_fail = 0;
uart_rsp->resvd = 0;
if(chnl_cb->status_cts != old_cts)
{
if(chnl_cb->status_cts == 0)
{
/* trigger send! */
mb_uart_send_data(chnl_cb);
}
}
return;
}
static void mb_uart_rx_isr(mb_uart_cb_t *chnl_cb, mb_chnl_cmd_t *cmd_buf)
{
/* overwrite the cmd_buf after the ISR handle completed.
* return the ack info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
mb_uart_rsp_t * uart_rsp = (mb_uart_rsp_t *)cmd_buf;
if(cmd_buf->hdr.cmd == MB_UART_SEND_DATA)
{
rx_isr_data_handler(chnl_cb, (mb_uart_cmd_t *)cmd_buf);
}
else if(cmd_buf->hdr.cmd == MB_UART_SEND_STATE)
{
rx_isr_state_handler(chnl_cb, (mb_uart_cmd_t *)cmd_buf);
}
else if(cmd_buf->hdr.cmd == MB_UART_ASSERT_DATA)
{
mb_uart_cmd_t * uart_cmd_buf = (mb_uart_cmd_t *)cmd_buf;
uart_cmd_buf->cmd_data_len--;
volatile u8 * busy_buf = (volatile u8 *)uart_cmd_buf->cmd_buff;
uart_cmd_buf->cmd_buff = (void *)(busy_buf + 1);
rx_isr_data_handler(chnl_cb, uart_cmd_buf);
busy_buf[0] = 0;
}
else
{
uart_rsp->uart_rts = chnl_cb->ctrl_rts;
uart_rsp->uart_tx_fail = 1;
uart_rsp->resvd = 0;
}
return;
}
static void mb_uart_tx_cmpl_isr(mb_uart_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf) /* tx_cmpl_isr */
{
mb_uart_rsp_t * uart_rsp = (mb_uart_rsp_t *)ack_buf;
u8 tx_fail = 0;
/* chnl_cb->rx_xchg_buff == uart_cmd->cmd_buff. MUST be true. */
if( (ack_buf->hdr.cmd != chnl_cb->tx_cmd) ||
(chnl_cb->tx_in_process == 0) )
{
/*
* !!! FAULT !!!
*/
BK_LOGE(MOD_TAG, "Fault tx_cmd:%x, rsp_cmd:%x\r\n", chnl_cb->tx_cmd, ack_buf->hdr.cmd);
return;
}
chnl_cb->tx_in_process = 0;
chnl_cb->status_cts = uart_rsp->uart_rts;
if(ack_buf->hdr.state & CHNL_STATE_COM_FAIL)
{
tx_fail = 0x01;
}
else
{
tx_fail = uart_rsp->uart_tx_fail;
}
/* try next Tx. */
/* trigger next Tx after saved cts and cleared tx_in_process. */
mb_uart_send_data(chnl_cb);
if(tx_fail)
{
// fail handle.
BK_LOGE(MOD_TAG, "Tx Failed!\r\n");
}
if(chnl_cb->tx_isr_callback != NULL)
{
chnl_cb->tx_isr_callback(chnl_cb->tx_isr_param);
}
return;
}
static bk_err_t mb_uart_init(mb_uart_cb_t *chnl_cb, u8 chnl_id)
{
bk_err_t ret_code;
if(chnl_cb->chnl_inited)
return BK_OK;
memset(chnl_cb, 0, sizeof(mb_uart_cb_t));
chnl_cb->chnl_id = chnl_id;
chnl_cb->tx_xchg_buff = mb_chnl_get_tx_buff(chnl_id);
chnl_cb->rx_xchg_buff = mb_chnl_get_rx_buff(chnl_id);
if( (chnl_cb->tx_xchg_buff == NULL) ||
(chnl_cb->tx_xchg_buff == NULL) )
{
return BK_FAIL;
}
ret_code = mb_chnl_open(chnl_id, chnl_cb);
if(ret_code != BK_OK)
{
return ret_code;
}
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_RX_ISR, (void *)mb_uart_rx_isr);
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_CMPL_ISR, (void *)mb_uart_tx_cmpl_isr);
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_ISR, NULL);
chnl_cb->chnl_inited = 1;
return BK_OK;
}
static bk_err_t mb_uart_deinit(mb_uart_cb_t *chnl_cb, u8 chnl_id)
{
if(!chnl_cb->chnl_inited)
return BK_OK;
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_RX_ISR, NULL);
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_CMPL_ISR, NULL);
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_ISR, NULL);
mb_chnl_close(chnl_id);
chnl_cb->rx_isr_callback = NULL;
chnl_cb->tx_isr_callback = NULL;
chnl_cb->chnl_inited = 0;
return BK_OK;
}
/* should be called in context of interrupt !* DISABLED *! . */
static bk_err_t mb_uart_send_data(mb_uart_cb_t *chnl_cb)
{
bk_err_t ret_val = BK_FAIL;
u16 rem_len, cpy_len;
mb_uart_cmd_t uart_cmd;
if(!chnl_cb->chnl_inited)
return BK_ERR_NOT_INIT;
if(chnl_cb->tx_data_cnt == 0)
return BK_OK;
if(chnl_cb->status_cts != 0)
{
return BK_ERR_BUSY;
}
if(chnl_cb->tx_in_process != 0)
{
return BK_ERR_BUSY;
}
cpy_len = chnl_cb->tx_data_cnt;
if(cpy_len > MB_UART_TX_FIFO_LEN)
{
cpy_len = MB_UART_TX_FIFO_LEN;
}
if(chnl_cb->tx_rd_idx < chnl_cb->tx_wr_idx)
{
memcpy(chnl_cb->tx_xchg_buff, chnl_cb->tx_buf + chnl_cb->tx_rd_idx, cpy_len);
chnl_cb->tx_rd_idx += cpy_len;
}
else
{
rem_len = sizeof(chnl_cb->tx_buf) - chnl_cb->tx_rd_idx;
if(rem_len > cpy_len)
{
memcpy(chnl_cb->tx_xchg_buff, chnl_cb->tx_buf + chnl_cb->tx_rd_idx, cpy_len);
chnl_cb->tx_rd_idx += cpy_len;
}
else
{
memcpy(chnl_cb->tx_xchg_buff, chnl_cb->tx_buf + chnl_cb->tx_rd_idx, rem_len);
if(rem_len < cpy_len)
{
memcpy(chnl_cb->tx_xchg_buff + rem_len, chnl_cb->tx_buf, cpy_len - rem_len);
}
chnl_cb->tx_rd_idx = cpy_len - rem_len;
}
}
chnl_cb->tx_data_cnt -= cpy_len;
chnl_cb->tx_in_process = 1;
chnl_cb->tx_cmd = MB_UART_SEND_DATA;
uart_cmd.chnl_hdr.data = 0; /* clear hdr. */
uart_cmd.chnl_hdr.cmd = MB_UART_SEND_DATA;
uart_cmd.cmd_buff = (void *)(chnl_cb->tx_xchg_buff);
uart_cmd.cmd_data_len = cpy_len;
uart_cmd.uart_rts = chnl_cb->ctrl_rts;
uart_cmd.resvd = 0;
uart_cmd.crc8 = cal_crc8_0x31(chnl_cb->tx_xchg_buff, cpy_len);
ret_val = mb_chnl_write(chnl_cb->chnl_id, (mb_chnl_cmd_t *)&uart_cmd);
if(ret_val != BK_OK)
{
chnl_cb->tx_in_process = 0; /* clear here, because no tx_cmpl_isr callback! */
}
return ret_val;
}
/* should be called in context of interrupt !* DISABLED *! . */
static bk_err_t mb_uart_send_state(mb_uart_cb_t *chnl_cb)
{
bk_err_t ret_val = BK_FAIL;
mb_uart_cmd_t uart_cmd;
if(!chnl_cb->chnl_inited)
return BK_ERR_NOT_INIT;
if(chnl_cb->tx_in_process != 0)
{
return BK_ERR_BUSY;
}
#if 1
if((chnl_cb->tx_data_cnt > 0) && (chnl_cb->status_cts == 0))
{
BK_LOGW(MOD_TAG, "pass in data,rts:%d\r\n", chnl_cb->ctrl_rts);
return BK_OK; /* rts state will be passed in send_data. */
}
#endif
chnl_cb->tx_in_process = 1;
chnl_cb->tx_cmd = MB_UART_SEND_STATE;
uart_cmd.chnl_hdr.data = 0; /* clear hdr. */
uart_cmd.chnl_hdr.cmd = MB_UART_SEND_STATE;
uart_cmd.cmd_buff = NULL;
uart_cmd.cmd_data_len = 0;
uart_cmd.uart_rts = chnl_cb->ctrl_rts;
uart_cmd.resvd = 0;
uart_cmd.crc8 = 0;
ret_val = mb_chnl_write(chnl_cb->chnl_id, (mb_chnl_cmd_t *)&uart_cmd);
if(ret_val != BK_OK)
{
chnl_cb->tx_in_process = 0; /* clear here, because no tx_cmpl_isr callback! */
}
return ret_val;
}
/* should be called in context of interrupt !* DISABLED *! . */
static u16 mb_uart_write_data(mb_uart_cb_t *chnl_cb, u8 * data_buf, u16 data_len)
{
u16 rem_len, wr_len;
if(!chnl_cb->chnl_inited)
return 0;
rem_len = sizeof(chnl_cb->tx_buf) - chnl_cb->tx_data_cnt;
wr_len = data_len;
if(wr_len > rem_len)
wr_len = rem_len;
if(chnl_cb->tx_wr_idx < chnl_cb->tx_rd_idx)
{
memcpy(chnl_cb->tx_buf + chnl_cb->tx_wr_idx, data_buf, wr_len);
chnl_cb->tx_wr_idx += wr_len;
}
else
{
rem_len = sizeof(chnl_cb->tx_buf) - chnl_cb->tx_wr_idx;
if(rem_len > wr_len)
{
memcpy(chnl_cb->tx_buf + chnl_cb->tx_wr_idx, data_buf, wr_len);
chnl_cb->tx_wr_idx += wr_len;
}
else
{
memcpy(chnl_cb->tx_buf + chnl_cb->tx_wr_idx, data_buf, rem_len);
if(rem_len < wr_len)
{
memcpy(chnl_cb->tx_buf, data_buf + rem_len, wr_len - rem_len);
}
chnl_cb->tx_wr_idx = wr_len - rem_len;
}
}
chnl_cb->tx_data_cnt += wr_len;
/* trigger send! */
mb_uart_send_data(chnl_cb);
return wr_len;
}
/* should be called in context of interrupt !* DISABLED *! . */
static bk_err_t mb_uart_write_sync(mb_uart_cb_t *chnl_cb, u8 * data_buf, u16 data_len)
{
volatile u8 * buff_busy;
u8 * tx_buff;
u16 cpy_len;
bk_err_t ret_code = BK_FAIL;
tx_buff = &chnl_cb->tx_xchg_buff[1];
buff_busy = (volatile u8 * )&chnl_cb->tx_xchg_buff[0];
while(data_len > 0)
{
cpy_len = MB_UART_TX_FIFO_LEN - 1;
if(cpy_len > data_len)
cpy_len = data_len;
buff_busy[0] = 1; /* the buffer is busy. */
memcpy(tx_buff, data_buf, cpy_len);
mb_uart_cmd_t uart_cmd;
uart_cmd.chnl_hdr.data = 0;
uart_cmd.chnl_hdr.cmd = MB_UART_ASSERT_DATA;
uart_cmd.cmd_buff = chnl_cb->tx_xchg_buff;
uart_cmd.cmd_data_len = cpy_len + 1;
uart_cmd.uart_rts = chnl_cb->ctrl_rts;
uart_cmd.resvd = 0;
uart_cmd.crc8 = cal_crc8_0x31((u8 *)tx_buff, cpy_len);
ret_code = mb_chnl_ctrl(chnl_cb->chnl_id, MB_CHNL_WRITE_SYNC, &uart_cmd);
if(ret_code == BK_OK)
{
while(*buff_busy)
{
// wait buffer to be free.
#if CONFIG_CACHE_ENABLE
flush_dcache((void *)buff_busy, 1);
#endif
}
}
else
{
break;
}
data_len -= cpy_len;
data_buf += cpy_len;
}
return ret_code;
}
/* should be called in context of interrupt !* DISABLED *! . */
static u16 mb_uart_read_data(mb_uart_cb_t *chnl_cb, u8 * data_buf, u16 buf_len)
{
u16 rem_len, rd_len;
if(!chnl_cb->chnl_inited)
return 0;
rd_len = chnl_cb->rx_data_cnt;
if(rd_len > buf_len)
rd_len = buf_len;
if(chnl_cb->rx_rd_idx < chnl_cb->rx_wr_idx)
{
memcpy(data_buf, chnl_cb->rx_buf + chnl_cb->rx_rd_idx, rd_len);
chnl_cb->rx_rd_idx += rd_len;
}
else
{
rem_len = sizeof(chnl_cb->rx_buf) - chnl_cb->rx_rd_idx;
if(rem_len > rd_len)
{
memcpy(data_buf, chnl_cb->rx_buf + chnl_cb->rx_rd_idx, rd_len);
chnl_cb->rx_rd_idx += rd_len;
}
else
{
memcpy(data_buf, chnl_cb->rx_buf + chnl_cb->rx_rd_idx, rem_len);
if(rem_len < rd_len)
{
memcpy(data_buf + rem_len, chnl_cb->rx_buf, rd_len - rem_len);
}
chnl_cb->rx_rd_idx = rd_len - rem_len;
}
}
chnl_cb->rx_data_cnt -= rd_len;
/* rts assert...... */
if(chnl_cb->rx_data_cnt < ((sizeof(chnl_cb->rx_buf) - MB_UART_RX_FIFO_LEN) * 8 / 10))
{
if( chnl_cb->ctrl_rts != 0)
{
chnl_cb->ctrl_rts = 0;
mb_uart_send_state(chnl_cb);
}
}
return rd_len;
}
/************************************************************************************
*
* mb_uart_driver API
*
************************************************************************************/
static mb_uart_cb_t mb_uart_cb[MB_UART_MAX];
static const u8 mb_uart_chnl_id[MB_UART_MAX] = {MB_CHNL_UART};
bk_err_t bk_mb_uart_dev_init(u8 id)
{
bk_err_t ret_val;
if(id >= MB_UART_MAX)
return BK_ERR_PARAM;
u32 int_mask = rtos_disable_int();
ret_val = mb_uart_init(&mb_uart_cb[id], mb_uart_chnl_id[id]);
mb_uart_send_state(&mb_uart_cb[id]);
rtos_enable_int(int_mask);
return ret_val;
}
bk_err_t bk_mb_uart_dev_deinit(u8 id)
{
bk_err_t ret_val;
if(id >= MB_UART_MAX)
return BK_ERR_PARAM;
u32 int_mask = rtos_disable_int();
ret_val = mb_uart_deinit(&mb_uart_cb[id], mb_uart_chnl_id[id]);
rtos_enable_int(int_mask);
return ret_val;
}
bk_err_t bk_mb_uart_register_rx_isr(u8 id, mb_uart_isr_t isr, void *param)
{
if(id >= MB_UART_MAX)
return BK_ERR_PARAM;
if(!mb_uart_cb[id].chnl_inited)
return BK_ERR_NOT_INIT;
u32 int_mask = rtos_disable_int();
mb_uart_cb[id].rx_isr_param = param; /* save rx_isr_param firstly! */
mb_uart_cb[id].rx_isr_callback = isr;
rtos_enable_int(int_mask);
return BK_OK;
}
bk_err_t bk_mb_uart_register_tx_isr(u8 id, mb_uart_isr_t isr, void *param)
{
if(id >= MB_UART_MAX)
return BK_ERR_PARAM;
if(!mb_uart_cb[id].chnl_inited)
return BK_ERR_NOT_INIT;
u32 int_mask = rtos_disable_int();
mb_uart_cb[id].tx_isr_param = param; /* save tx_isr_param firstly! */
mb_uart_cb[id].tx_isr_callback = isr;
rtos_enable_int(int_mask);
return BK_OK;
}
u16 bk_mb_uart_write_ready(u8 id)
{
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
return (sizeof(mb_uart_cb[id].tx_buf) - mb_uart_cb[id].tx_data_cnt);
}
u16 bk_mb_uart_read_ready(u8 id)
{
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
return (mb_uart_cb[id].rx_data_cnt);
}
u16 bk_mb_uart_write_byte(u8 id, u8 data)
{
u16 len;
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
u32 int_mask = rtos_disable_int();
len = mb_uart_write_data(&mb_uart_cb[id], &data, 1);
rtos_enable_int(int_mask);
return len;
}
u16 bk_mb_uart_write(u8 id, u8 *data_buf, u16 data_len)
{
u16 len;
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
if((data_buf == NULL) || (data_len == 0))
return 0;
u32 int_mask = rtos_disable_int();
len = mb_uart_write_data(&mb_uart_cb[id], data_buf, data_len);
rtos_enable_int(int_mask);
return len;
}
u16 bk_mb_uart_read_byte(u8 id, u8 * data)
{
u16 len;
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
if(data == NULL)
return 0;
u32 int_mask = rtos_disable_int();
len = mb_uart_read_data(&mb_uart_cb[id], data, 1);
rtos_enable_int(int_mask);
return len;
}
u16 bk_mb_uart_read(u8 id, u8 *data_buf, u16 buf_len)
{
u16 len;
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
if((data_buf == NULL) || (buf_len == 0))
return 0;
u32 int_mask = rtos_disable_int();
len = mb_uart_read_data(&mb_uart_cb[id], data_buf, buf_len);
rtos_enable_int(int_mask);
return len;
}
bool bk_mb_uart_is_tx_over(u8 id)
{
#if 1
if(id >= MB_UART_MAX)
return 1;
if(!mb_uart_cb[id].chnl_inited)
return 1;
if( (mb_uart_cb[id].tx_data_cnt == 0) &&
(mb_uart_cb[id].tx_in_process == 0) )
{
return 1;
}
return 0;
#else
return 1;
#endif
}
bk_err_t bk_mb_uart_dump(u8 id, u8 *data_buf, u16 data_len)
{
bk_err_t ret_val;
if(id >= MB_UART_MAX)
return BK_ERR_PARAM;
if(!mb_uart_cb[id].chnl_inited)
return BK_ERR_NOT_INIT;
u32 int_mask = rtos_disable_int();
ret_val = mb_uart_write_sync(&mb_uart_cb[id], data_buf, data_len);
rtos_enable_int(int_mask);
return ret_val;
}
u16 bk_mb_uart_get_status(u8 id)
{
u16 status = 0;
if(id >= MB_UART_MAX)
return 0;
if(!mb_uart_cb[id].chnl_inited)
return 0;
if(mb_uart_cb[id].status_overflow)
{
status |= MB_UART_STATUS_OVF;
mb_uart_cb[id].status_overflow = 0;
}
if(mb_uart_cb[id].status_parity)
{
status |= MB_UART_STATUS_PARITY_ERR;
mb_uart_cb[id].status_parity = 0;
}
return status;
}
#endif