📄 serial.c
字号:
extern int enable_diag_uart;
int _enable = enable_diag_uart;
int _time, _stime;
externC cyg_tick_count_t cyg_current_time(void);
#endif // CYGDBG_DIAG_BUF
cyg_drv_mutex_lock(&cbuf->lock);
cbuf->abort = false;
if (cbuf->len == 0) {
// Non interrupt driven (i.e. polled) operation
while (size++ < *len) {
cyg_uint8 c = (funs->getc)(chan);
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
// for software flow control, if the driver returns one of the
// characters we act on it and then drop it (the app must not
// see it)
if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_TX ) {
if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR ) {
throttle_tx( chan );
} else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) {
restart_tx( chan );
}
else
*buf++ = c;
}
else
*buf++ = c;
#else
*buf++ = c;
#endif
}
} else {
cyg_drv_dsr_lock(); // Avoid races
while (size < *len) {
if (cbuf->nb > 0) {
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
if ( (cbuf->nb <= cbuf->low_water) &&
(chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) )
restart_rx( chan, false );
#endif
*buf++ = cbuf->data[cbuf->get];
if (++cbuf->get == cbuf->len) cbuf->get = 0;
cbuf->nb--;
size++;
} else {
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
if (!cbuf->blocking) {
*len = size; // characters actually read
res = size == 0 ? -EAGAIN : ENOERR;
break;
}
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
cbuf->waiting = true;
#ifdef XX_CYGDBG_DIAG_BUF
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("READ wait - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time);
enable_diag_uart = _enable;
#endif // CYGDBG_DIAG_BUF
if( !cyg_drv_cond_wait(&cbuf->wait) )
cbuf->abort = true;
#ifdef XX_CYGDBG_DIAG_BUF
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("READ continue - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time);
enable_diag_uart = _enable;
#endif // CYGDBG_DIAG_BUF
if (cbuf->abort) {
// Give up!
*len = size; // characters actually read
cbuf->abort = false;
cbuf->waiting = false;
res = -EINTR;
break;
}
}
}
cyg_drv_dsr_unlock();
}
#ifdef XX_CYGDBG_DIAG_BUF
cyg_drv_isr_lock();
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("READ done - size: %d, len: %d, time: %x.%x\n", size, *len, _stime, _time);
enable_diag_uart = _enable;
cyg_drv_isr_unlock();
#endif // CYGDBG_DIAG_BUF
cyg_drv_mutex_unlock(&cbuf->lock);
return res;
}
// ---------------------------------------------------------------------------
static cyg_bool
serial_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
{
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
serial_channel *chan = (serial_channel *)t->priv;
switch( which )
{
case CYG_FREAD:
{
cbuf_t *cbuf = &chan->in_cbuf;
// Check for data in the input buffer. If there is none,
// register the select operation, otherwise return true.
if( cbuf->nb == 0 )
cyg_selrecord( info, &cbuf->selinfo );
else return true;
}
break;
case CYG_FWRITE:
{
// Check for space in the output buffer. If there is none,
// register the select operation, otherwise return true.
cbuf_t *cbuf = &chan->out_cbuf;
int space = cbuf->len - cbuf->nb;
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
if ( (space < cbuf->low_water) ||
(chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
cyg_selrecord( info, &cbuf->selinfo );
#else
if (space < cbuf->low_water)
cyg_selrecord( info, &cbuf->selinfo );
#endif
else return true;
}
break;
case 0: // exceptions - none supported
break;
}
return false;
#else
// With no select support, we simply return true.
return true;
#endif
}
// ---------------------------------------------------------------------------
static Cyg_ErrNo
serial_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf,
cyg_uint32 *len)
{
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
serial_channel *chan = (serial_channel *)t->priv;
cyg_serial_info_t *buf = (cyg_serial_info_t *)xbuf;
Cyg_ErrNo res = ENOERR;
cbuf_t *out_cbuf = &chan->out_cbuf;
cbuf_t *in_cbuf = &chan->in_cbuf;
serial_funs *funs = chan->funs;
switch (key) {
case CYG_IO_GET_CONFIG_SERIAL_INFO:
if (*len < sizeof(cyg_serial_info_t)) {
return -EINVAL;
}
*buf = chan->config;
*len = sizeof(chan->config);
break;
case CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO:
// return rx/tx buffer sizes and counts
{
cyg_serial_buf_info_t *p;
if (*len < sizeof(cyg_serial_buf_info_t))
return -EINVAL;
*len = sizeof(cyg_serial_buf_info_t);
p = (cyg_serial_buf_info_t *)xbuf;
p->rx_bufsize = in_cbuf->len;
if (p->rx_bufsize)
p->rx_count = in_cbuf->nb;
else
p->rx_count = 0;
p->tx_bufsize = out_cbuf->len;
if (p->tx_bufsize)
p->tx_count = out_cbuf->nb;
else
p->tx_count = 0;
}
break;
case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
// Wait for any pending output to complete
if (out_cbuf->len == 0) break; // Nothing to do if not buffered
cyg_drv_mutex_lock(&out_cbuf->lock); // Stop any further output processing
cyg_drv_dsr_lock();
while (out_cbuf->pending || (out_cbuf->nb > 0)) {
out_cbuf->waiting = true;
if(!cyg_drv_cond_wait(&out_cbuf->wait) )
res = -EINTR;
}
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&out_cbuf->lock);
break;
case CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH:
// Flush any buffered input
if (in_cbuf->len == 0) break; // Nothing to do if not buffered
cyg_drv_mutex_lock(&in_cbuf->lock); // Stop any further input processing
cyg_drv_dsr_lock();
if (in_cbuf->waiting) {
in_cbuf->abort = true;
cyg_drv_cond_broadcast(&in_cbuf->wait);
in_cbuf->waiting = false;
}
in_cbuf->get = in_cbuf->put = in_cbuf->nb = 0; // Flush buffered input
// Pass to the hardware driver in case it wants to flush FIFOs etc.
(funs->set_config)(chan,
CYG_IO_SET_CONFIG_SERIAL_INPUT_FLUSH,
NULL, NULL);
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&in_cbuf->lock);
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
// Restart receiver if it was shutdown
if ((chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) != 0) {
restart_rx( chan, false );
}
#endif
break;
case CYG_IO_GET_CONFIG_SERIAL_ABORT:
// Abort any outstanding I/O, including blocked reads
// Caution - assumed to be called from 'timeout' (i.e. DSR) code
if (in_cbuf->len != 0) {
in_cbuf->abort = true;
cyg_drv_cond_broadcast(&in_cbuf->wait);
}
if (out_cbuf->len != 0) {
out_cbuf->abort = true;
cyg_drv_cond_broadcast(&out_cbuf->wait);
}
break;
case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_FLUSH:
// Throw away any pending output
if (out_cbuf->len == 0) break; // Nothing to do if not buffered
cyg_drv_mutex_lock(&out_cbuf->lock); // Stop any further output processing
cyg_drv_dsr_lock();
if (out_cbuf->nb > 0) {
out_cbuf->get = out_cbuf->put = out_cbuf->nb = 0; // Empties queue!
(funs->stop_xmit)(chan); // Done with transmit
}
// Pass to the hardware driver in case it wants to flush FIFOs etc.
(funs->set_config)(chan,
CYG_IO_SET_CONFIG_SERIAL_OUTPUT_FLUSH,
NULL, NULL);
if (out_cbuf->waiting) {
out_cbuf->abort = true;
cyg_drv_cond_broadcast(&out_cbuf->wait);
out_cbuf->waiting = false;
}
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&out_cbuf->lock);
break;
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
case CYG_IO_GET_CONFIG_READ_BLOCKING:
if (*len < sizeof(cyg_uint32)) {
return -EINVAL;
}
*(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
break;
case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
if (*len < sizeof(cyg_uint32)) {
return -EINVAL;
}
*(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
break;
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
default:
res = -EINVAL;
}
return res;
}
// ---------------------------------------------------------------------------
static Cyg_ErrNo
serial_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf,
cyg_uint32 *len)
{
Cyg_ErrNo res = ENOERR;
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
serial_channel *chan = (serial_channel *)t->priv;
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
cbuf_t *out_cbuf = &chan->out_cbuf;
cbuf_t *in_cbuf = &chan->in_cbuf;
#endif
serial_funs *funs = chan->funs;
switch (key) {
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
case CYG_IO_SET_CONFIG_READ_BLOCKING:
if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) {
return -EINVAL;
}
in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
break;
case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) {
return -EINVAL;
}
out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
break;
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
case CYG_IO_SET_CONFIG_SERIAL_FLOW_CONTROL_METHOD:
{
cyg_uint32 *f = (cyg_uint32 *)xbuf;
if (*len < sizeof(*f))
return -EINVAL;
cyg_drv_dsr_lock();
chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|
CYGNUM_SERIAL_FLOW_XONXOFF_TX|
CYGNUM_SERIAL_FLOW_RTSCTS_RX|
CYGNUM_SERIAL_FLOW_RTSCTS_TX|
CYGNUM_SERIAL_FLOW_DSRDTR_RX|
CYGNUM_SERIAL_FLOW_DSRDTR_TX);
chan->config.flags |= (*f & (
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
CYGNUM_SERIAL_FLOW_XONXOFF_RX|
CYGNUM_SERIAL_FLOW_XONXOFF_TX|
#endif
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
CYGNUM_SERIAL_FLOW_RTSCTS_RX|
CYGNUM_SERIAL_FLOW_RTSCTS_TX|
CYGNUM_SERIAL_FLOW_DSRDTR_RX|
CYGNUM_SERIAL_FLOW_DSRDTR_TX|
#endif
0));
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
// up to hardware driver to clear flags if rejected
res = (funs->set_config)(chan,
CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG,
NULL, NULL);
#endif
cyg_drv_dsr_unlock();
}
break;
case CYG_IO_SET_CONFIG_SERIAL_FLOW_CONTROL_FORCE:
{
cyg_uint32 *f = (cyg_uint32 *)xbuf;
if (*len < sizeof(*f))
return -EINVAL;
cyg_drv_dsr_lock();
switch (*f) {
case CYGNUM_SERIAL_FLOW_THROTTLE_RX:
throttle_rx( chan, true );
break;
case CYGNUM_SERIAL_FLOW_RESTART_RX:
restart_rx( chan, true );
break;
case CYGNUM_SERIAL_FLOW_THROTTLE_TX:
throttle_tx( chan );
break;
case CYGNUM_SERIAL_FLOW_RESTART_TX:
restart_tx( chan );
break;
default:
res = -EINVAL;
break;
}
cyg_drv_dsr_unlock();
}
break;
#endif // CYGPKG_IO_SERIAL_FLOW_CONTROL
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
case CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK:
{
cyg_serial_line_status_callback_fn_t newfn;
CYG_ADDRWORD newpriv;
cyg_serial_line_status_callback_t *tmp =
(cyg_serial_line_status_callback_t *)xbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -