⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
            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 + -