559 lines
13 KiB
C
559 lines
13 KiB
C
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
#include <rthw.h>
|
|
|
|
#include <chrg_tty.h>
|
|
|
|
#define DBG_TAG "chrg.tty"
|
|
#define DBG_LVL DBG_LOG
|
|
#include <rtdbg.h>
|
|
|
|
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
static rt_err_t chrg_tty_send_comp_hook (rt_device_t dev, void *buffer)
|
|
{
|
|
struct chrg_tty_t *pTTY = (struct chrg_tty_t *)(dev->user_data);
|
|
rt_completion_done(&pTTY->tx_comp);
|
|
|
|
return (RT_EOK);
|
|
}
|
|
#endif
|
|
|
|
static rt_err_t chrg_tty_recv_ind_hook (rt_device_t dev, rt_size_t size)
|
|
{
|
|
struct chrg_tty_t *pTTY = (struct chrg_tty_t *)(dev->user_data);
|
|
if (pTTY->evt) {
|
|
rt_event_send(pTTY->evt, TTY_EVT_RX_IND);
|
|
}
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
static int chrg_tty_cal_byte_tmo (int baudrate)
|
|
{
|
|
int tmo = (40 * 1000) / baudrate;
|
|
|
|
if (tmo < TTY_BYTE_TMO_MIN) {
|
|
tmo = TTY_BYTE_TMO_MIN;
|
|
} else if (tmo > TTY_BYTE_TMO_MAX) {
|
|
tmo = TTY_BYTE_TMO_MAX;
|
|
}
|
|
|
|
return (tmo);
|
|
}
|
|
|
|
// mode : 0--receive mode, 1--send mode
|
|
void chrg_tty_mode_set (struct chrg_tty_t *pTTY, int mode)
|
|
{
|
|
if (pTTY->pin < 0) {
|
|
return;
|
|
}
|
|
|
|
if (mode) {
|
|
rt_pin_write(pTTY->pin, pTTY->level);
|
|
#if (TTY_SW_DLY_US > 0)
|
|
rt_hw_us_delay(TTY_SW_DLY_US);
|
|
#endif
|
|
} else {
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
rt_completion_wait(&pTTY->tx_comp, TTY_TX_COMP_TMO_MAX);
|
|
rt_thread_mdelay(pTTY->tx_dly_ms); // 等待末尾数据传输完成
|
|
|
|
#elif (TTY_SW_DLY_US > 0)
|
|
rt_hw_us_delay(TTY_SW_DLY_US);
|
|
#endif
|
|
|
|
rt_pin_write(pTTY->pin, !pTTY->level);
|
|
}
|
|
}
|
|
|
|
static int chrg_tty_dev_open (struct chrg_tty_t *pTTY)
|
|
{
|
|
rt_err_t ret = RT_EOK;
|
|
|
|
#ifdef TTY_USING_DMA_RX
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
#endif
|
|
|
|
#ifdef TTY_USING_INT_TX
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_INT_TX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
#endif
|
|
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
#endif
|
|
|
|
#ifdef TTY_USING_INT_TX
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
#endif
|
|
|
|
ret = rt_device_open(pTTY->dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
|
|
if (RT_EOK == ret) {
|
|
return (RT_EOK);
|
|
}
|
|
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
/*
|
|
* @brief create tty instance dynamically
|
|
* @param name - serial device name
|
|
* @param baudrate - serial baud rate
|
|
* @param parity - serial parity mode
|
|
* @param pin - mode contrle pin
|
|
* @param level - send mode level
|
|
* @retval instance handle
|
|
*/
|
|
struct chrg_tty_t *chrg_tty_create (const char *devname, int baudrate, int parity, int pin, int level)
|
|
{
|
|
struct chrg_tty_t *pTTY = RT_NULL;
|
|
rt_device_t dev;
|
|
|
|
dev = rt_device_find(devname);
|
|
if (RT_NULL == dev) {
|
|
LOG_E("tty device '%s' not found.", devname);
|
|
return (RT_NULL);
|
|
}
|
|
|
|
if (RT_Device_Class_Char != dev->type) {
|
|
LOG_E("tty device '%s' type is not char.", devname);
|
|
return (RT_NULL);
|
|
}
|
|
|
|
pTTY = (struct chrg_tty_t *)rt_malloc(sizeof(struct chrg_tty_t));
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("no memory for tty create instance.");
|
|
return (RT_NULL);
|
|
}
|
|
|
|
pTTY->devname = devname;
|
|
pTTY->lock = rt_mutex_create(devname, RT_IPC_FLAG_FIFO);
|
|
if (RT_NULL == pTTY->lock) {
|
|
rt_free(pTTY);
|
|
LOG_E("create mutex failed.");
|
|
return (RT_NULL);
|
|
}
|
|
|
|
pTTY->evt = rt_event_create(devname, RT_IPC_FLAG_FIFO);
|
|
if (RT_NULL == pTTY->evt) {
|
|
rt_mutex_delete(pTTY->lock);
|
|
rt_free(pTTY);
|
|
LOG_E("create event failed.");
|
|
return (RT_NULL);
|
|
}
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
pTTY->tx_dly_ms = ((2 * 11 *1000) / baudrate) + 1;
|
|
rt_completion_init(&pTTY->tx_comp);
|
|
#endif
|
|
|
|
pTTY->dev = dev;
|
|
pTTY->status = 0;
|
|
pTTY->pin = pin;
|
|
pTTY->level = (level != 0);
|
|
pTTY->timeout = 0;
|
|
pTTY->byte_tmo = chrg_tty_cal_byte_tmo(baudrate);
|
|
|
|
chrg_tty_config(pTTY, baudrate, 8, parity, 0);
|
|
|
|
return pTTY;
|
|
}
|
|
|
|
/*
|
|
* @brief destory tty instance created dynamically
|
|
* @param pTTY - instance handle
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_destory (struct chrg_tty_t *pTTY)
|
|
{
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
chrg_tty_disconn(pTTY);
|
|
|
|
if (pTTY->lock) {
|
|
rt_mutex_delete(pTTY->lock);
|
|
pTTY->lock = RT_NULL;
|
|
}
|
|
|
|
if (pTTY->evt) {
|
|
rt_event_delete(pTTY->evt);
|
|
pTTY->evt = RT_NULL;
|
|
}
|
|
|
|
rt_free(pTTY);
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief config tty params
|
|
* @param pTTY - instance handle
|
|
* @param baudrate - baudrate of communication
|
|
* @param databits - data bits, 5~8
|
|
* @param parity - parity bit, 0~2, 0 - none, 1 - odd, 2 - even
|
|
* @param stopbits - stop bits, 0~1, 0 - 1 stop bit, 1 - 2 stop bits
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_config (struct chrg_tty_t *pTTY,
|
|
int baudrate, int databits, int parity, int stopbits)
|
|
{
|
|
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
|
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
pTTY->tx_dly_ms = ((2 * 11 *1000) / baudrate) + 1;
|
|
#endif
|
|
|
|
pTTY->byte_tmo = chrg_tty_cal_byte_tmo(baudrate);
|
|
|
|
config.baud_rate = baudrate;
|
|
config.data_bits = databits;
|
|
config.parity = parity;
|
|
config.stop_bits = stopbits;
|
|
rt_device_control(pTTY->dev, RT_DEVICE_CTRL_CONFIG, &config);
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief set wait datas timeout for receiving
|
|
* @param pTTY - instance handle
|
|
* @param tmo_ms - receive wait timeout, 0--no wait, <0--wait forever, >0--wait timeout, default = 0
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_set_recv_tmo (struct chrg_tty_t *pTTY, int tmo_ms)
|
|
{
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
pTTY->timeout = tmo_ms;
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief set byte interval timeout for receiving
|
|
* @param pTTY - instance handle
|
|
* @param tmo_ms - byte interval timeout, default is calculated from baudrate
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_set_byte_tmo (struct chrg_tty_t *pTTY, int tmo_ms)
|
|
{
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
if (tmo_ms < TTY_BYTE_TMO_MIN) {
|
|
tmo_ms = TTY_BYTE_TMO_MIN;
|
|
} else if (tmo_ms > TTY_BYTE_TMO_MAX) {
|
|
tmo_ms = TTY_BYTE_TMO_MAX;
|
|
}
|
|
|
|
pTTY->byte_tmo = tmo_ms;
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief open tty connect
|
|
* @param pTTY - instance handle
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_connect (struct chrg_tty_t * pTTY)
|
|
{
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
if (pTTY->status == 1) {
|
|
return RT_EOK;
|
|
}
|
|
|
|
if (chrg_tty_dev_open(pTTY) != RT_EOK) {
|
|
LOG_E("tty open failed.");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
if (pTTY->pin >= 0) {
|
|
rt_pin_mode(pTTY->pin, PIN_MODE_OUTPUT);
|
|
rt_pin_write(pTTY->pin, !pTTY->level);
|
|
}
|
|
|
|
|
|
pTTY->dev->user_data = pTTY;
|
|
pTTY->dev->rx_indicate = chrg_tty_recv_ind_hook;
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
pTTY->dev->tx_complete = chrg_tty_send_comp_hook;
|
|
#endif
|
|
|
|
pTTY->status = 1;
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief close tty connect
|
|
* @param pTTY - instance handle
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_disconn (struct chrg_tty_t *pTTY)
|
|
{
|
|
if (RT_NULL == pTTY) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
if (pTTY->status == 0) {
|
|
return(RT_EOK);
|
|
}
|
|
|
|
rt_mutex_take(pTTY->lock, RT_WAITING_FOREVER);
|
|
|
|
if (pTTY->dev) {
|
|
pTTY->dev->rx_indicate = RT_NULL;
|
|
|
|
#ifdef TTY_USING_DMA_TX
|
|
pTTY->dev->tx_complete = RT_NULL;
|
|
#endif
|
|
|
|
rt_device_close(pTTY->dev);
|
|
}
|
|
|
|
if (pTTY->pin >= 0) {
|
|
rt_pin_mode(pTTY->pin, PIN_MODE_INPUT);
|
|
}
|
|
|
|
pTTY->status = 0;
|
|
|
|
rt_mutex_release(pTTY->lock);
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief receive datas from tty
|
|
* @param pTTY - instance handle
|
|
* @param buf - buffer addr
|
|
* @param size - maximum length of received datas
|
|
* @retval >=0 - length of received datas, <0 - error
|
|
*/
|
|
int chrg_tty_recv (struct chrg_tty_t *pTTY, void *buf, int size)
|
|
{
|
|
rt_err_t ret = RT_EOK;
|
|
int recv_len = 0;
|
|
rt_uint32_t recved = 0;
|
|
|
|
if (pTTY == RT_NULL || buf == RT_NULL || size == 0) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
if (pTTY->status == 0) {
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
ret = rt_mutex_take(pTTY->lock, RT_WAITING_FOREVER);
|
|
if (RT_EOK != ret) {
|
|
LOG_E("mutex take failed. [%d]", ret);
|
|
return(-RT_ERROR);
|
|
}
|
|
|
|
while (size) {
|
|
int len = rt_device_read(pTTY->dev, 0, (char *)buf + recv_len, size);
|
|
if (len) {
|
|
recv_len += len;
|
|
size -= len;
|
|
continue;
|
|
}
|
|
|
|
rt_event_control(pTTY->evt, RT_IPC_CMD_RESET, RT_NULL);
|
|
|
|
if (recv_len) {
|
|
ret = rt_event_recv(pTTY->evt, TTY_EVT_RX_IND,
|
|
(RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), pTTY->byte_tmo, &recved);
|
|
if (RT_EOK != ret) {
|
|
break;
|
|
}
|
|
} else {
|
|
ret = rt_event_recv(pTTY->evt, (TTY_EVT_RX_IND | TTY_EVT_RX_BREAK),
|
|
(RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), pTTY->timeout, &recved);
|
|
if (RT_EOK != ret) {
|
|
break;
|
|
}
|
|
|
|
if ((recved & TTY_EVT_RX_BREAK) != 0) {
|
|
rt_mutex_release(pTTY->lock);
|
|
rt_thread_delay(2);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
rt_mutex_release(pTTY->lock);
|
|
|
|
return recv_len;
|
|
}
|
|
|
|
/*
|
|
* @brief send datas to tty
|
|
* @param pTTY - instance handle
|
|
* @param buf - buffer addr
|
|
* @param size - length of send datas
|
|
* @retval >=0 - length of sent datas, <0 - error
|
|
*/
|
|
int chrg_tty_send (struct chrg_tty_t *pTTY, void *buf, int size)
|
|
{
|
|
rt_err_t ret = RT_EOK;
|
|
int send_len = 0;
|
|
|
|
if (pTTY == RT_NULL || buf == RT_NULL || size == 0) {
|
|
LOG_E("param null.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
if (pTTY->status == 0) {
|
|
LOG_E("tty not connected.");
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
ret = rt_mutex_take(pTTY->lock, RT_WAITING_FOREVER);
|
|
if (RT_EOK != ret) {
|
|
LOG_E("mutex take failed. [%d]", ret);
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
chrg_tty_mode_set(pTTY, 1);//set to send mode
|
|
send_len = rt_device_write(pTTY->dev, 0, buf, size);
|
|
chrg_tty_mode_set(pTTY, 0);//set to receive mode
|
|
|
|
rt_mutex_release(pTTY->lock);
|
|
|
|
return send_len;
|
|
}
|
|
|
|
/*
|
|
* @brief break tty receive wait
|
|
* @param pTTY - instance handle
|
|
* @retval 0 - success, other - error
|
|
*/
|
|
int chrg_tty_break_recv (struct chrg_tty_t *pTTY)
|
|
{
|
|
if ((pTTY == RT_NULL) || (pTTY->evt == RT_NULL)) {
|
|
return (-RT_ERROR);
|
|
}
|
|
|
|
rt_event_send(pTTY->evt, TTY_EVT_RX_BREAK);
|
|
|
|
return (RT_EOK);
|
|
}
|
|
|
|
/*
|
|
* @brief send data to tty and then receive response data from tty
|
|
* @param pTTY - instance handle
|
|
* @param send_buf - send buffer addr
|
|
* @param send_len - length of send datas
|
|
* @param recv_buf - recv buffer addr
|
|
* @param recv_size - maximum length of received datas
|
|
* @retval >=0 - length of received datas, <0 - error
|
|
*/
|
|
int chrg_tty_send_then_recv (struct chrg_tty_t *pTTY,
|
|
void *send_buf, int send_len, void *recv_buf, int recv_size)
|
|
{
|
|
rt_err_t ret = RT_EOK;
|
|
int recv_len = 0;
|
|
rt_uint32_t recved = 0;
|
|
|
|
if (pTTY == RT_NULL || send_buf == RT_NULL || send_len == 0 || recv_buf == RT_NULL || recv_size == 0) {
|
|
LOG_E("null param");
|
|
return(-RT_ERROR);
|
|
}
|
|
|
|
if (pTTY->status == 0) {
|
|
LOG_E("tty not connected.");
|
|
return(-RT_ERROR);
|
|
}
|
|
|
|
ret = rt_mutex_take(pTTY->lock, RT_WAITING_FOREVER);
|
|
if (RT_EOK != ret) {
|
|
LOG_E("mutex take failed. [%d]", ret);
|
|
return(-RT_ERROR);
|
|
}
|
|
|
|
chrg_tty_mode_set(pTTY, 1);//set to send mode
|
|
send_len = rt_device_write(pTTY->dev, 0, send_buf, send_len);
|
|
chrg_tty_mode_set(pTTY, 0);//set to receive mode
|
|
if (send_len < 0) {
|
|
rt_mutex_release(pTTY->lock);
|
|
LOG_E("send error.");
|
|
return(-RT_ERROR);
|
|
}
|
|
|
|
while (recv_size) {
|
|
int len = rt_device_read(pTTY->dev, 0, (char *)recv_buf + recv_len, recv_size);
|
|
if (len) {
|
|
recv_len += len;
|
|
recv_size -= len;
|
|
continue;
|
|
}
|
|
|
|
rt_event_control(pTTY->evt, RT_IPC_CMD_RESET, RT_NULL);
|
|
|
|
if (recv_len) {
|
|
ret = rt_event_recv(pTTY->evt, TTY_EVT_RX_IND,
|
|
(RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), pTTY->byte_tmo, &recved);
|
|
if (RT_EOK != ret) {
|
|
break;
|
|
}
|
|
} else {
|
|
ret = rt_event_recv(pTTY->evt, TTY_EVT_RX_IND,
|
|
(RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), pTTY->timeout, &recved);
|
|
if (RT_EOK != ret) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
rt_mutex_release(pTTY->lock);
|
|
|
|
return recv_len;
|
|
}
|
|
|
|
|
|
|