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

📄 serial.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
                        if ( *len < sizeof(*tmp) )                return -EINVAL;            newfn = tmp->fn;            newpriv = tmp->priv;            // prevent callbacks while we do this            cyg_drv_dsr_lock();            // store old callbacks in same structure            tmp->fn = chan->status_callback;            tmp->priv = chan->status_callback_priv;            chan->status_callback = newfn;            chan->status_callback_priv = newpriv;            cyg_drv_dsr_unlock();            *len = sizeof(*tmp);        }          break;#endif    default:        // pass down to lower layers        return (funs->set_config)(chan, key, xbuf, len);    }    return res;}// ---------------------------------------------------------------------------static voidserial_xmt_char(serial_channel *chan){    cbuf_t *cbuf = &chan->out_cbuf;    serial_funs *funs = chan->funs;    unsigned char c;    int space;#if CYGINT_IO_SERIAL_BLOCK_TRANSFER    CYG_ASSERT(false == cbuf->block_mode_xfer_running,               "Attempting char xmt while block transfer is running");#endif#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    // if we are required to send an XON/XOFF char, send it before    // anything else    // FIXME: what if XON gets corrupted in transit to the other end?    // Should we resend XON even though the other end may not be wanting    // to send us stuff at this point?    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) {        if ( chan->flow_desc.xchar ) {            if ( (funs->putc)(chan, chan->flow_desc.xchar) ) {                chan->flow_desc.xchar = '\0';            } else {  // otherwise there's no space and we have to wait                return;            }        }    }#endif#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL    // if we're meant to be throttled, just stop and leave    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {        (funs->stop_xmit)(chan);  // Stop transmitting for now        return;    }#endif    while (cbuf->nb > 0) {        c = cbuf->data[cbuf->get];        if ((funs->putc)(chan, c)) {            cbuf->get++;            if (cbuf->get == cbuf->len) cbuf->get = 0;            cbuf->nb--;        } else {            // See if there is now enough room to restart writer            space = cbuf->len - cbuf->nb;            if (space >= cbuf->low_water) {                if (cbuf->waiting) {                    cbuf->waiting = false;                    cyg_drv_cond_broadcast(&cbuf->wait);                }#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT                cyg_selwakeup( &cbuf->selinfo );#endif                                }            return;  // Need to wait for more space        }    }    (funs->stop_xmit)(chan);  // Done with transmit    // must signal waiters, and wake up selecters for the case when    // this was the last char to be sent and they hadn't been signalled    // before (e.g. because of flow control)    if (cbuf->waiting) {        cbuf->waiting = false;        cyg_drv_cond_broadcast(&cbuf->wait);    }#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT    cyg_selwakeup( &cbuf->selinfo );#endif                    }// ---------------------------------------------------------------------------static voidserial_rcv_char(serial_channel *chan, unsigned char c){    cbuf_t *cbuf = &chan->in_cbuf;#if CYGINT_IO_SERIAL_BLOCK_TRANSFER    CYG_ASSERT(false == cbuf->block_mode_xfer_running,               "Attempting char rcv while block transfer is running");#endif#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 );            return; // it wasn't a "real" character        } else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) {            restart_tx( chan );            return; // it wasn't a "real" character        }    }#endif    #ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL    // If we've hit the high water mark, tell the other side to stop    if ( cbuf->nb >= cbuf->high_water ) {        throttle_rx( chan, false );    }#endif#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT    // Wake up any pending selectors if we are about to    // put some data into a previously empty buffer.    if( cbuf->nb == 0 )        cyg_selwakeup( &cbuf->selinfo );#endif    // If the flow control is not enabled/sufficient and the buffer is    // already full, just throw new characters away.    if ( cbuf->nb < cbuf->len ) {        cbuf->data[cbuf->put++] = c;        if (cbuf->put == cbuf->len) cbuf->put = 0;        cbuf->nb++;    } // note trailing else#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS    else {        // Overrun. Report the error.        cyg_serial_line_status_t stat;        stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;        serial_indicate_status(chan, &stat);    }#endif    if (cbuf->waiting) {#ifdef XX_CYGDBG_DIAG_BUF            extern int enable_diag_uart;            int _enable = enable_diag_uart;            int _time, _stime;            externC cyg_tick_count_t cyg_current_time(void);            enable_diag_uart = 0;            HAL_CLOCK_READ(&_time);            _stime = (int)cyg_current_time();            diag_printf("Signal reader - time: %x.%x\n", _stime, _time);            enable_diag_uart = _enable;#endif // CYGDBG_DIAG_BUF        cbuf->waiting = false;        cyg_drv_cond_broadcast(&cbuf->wait);    }}//----------------------------------------------------------------------------// Flow control indication callback#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUSstatic voidserial_indicate_status(serial_channel *chan, cyg_serial_line_status_t *s ){#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL    if ( CYGNUM_SERIAL_STATUS_FLOW == s->which ) {        if ( s->value )            restart_tx( chan );        else            throttle_tx( chan );    }#endif    if ( chan->status_callback )        (*chan->status_callback)(s, chan->status_callback_priv);}#endif // ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS//----------------------------------------------------------------------------// Block transfer functions. Not all drivers require these. Those that// do must follow the required semantics://// Attempt to transfer as much via the block transfer function as// possible, _but_ if that fails, do the remaining bytes via the// single-char function. That ensures that all policy decisions can be// made in this driver, and not in the device driver.//// Note: if the driver uses DMA for transmission, an initial failing// call to the xmt_req function must cause the start_xmit function to// fall-back to regular CPU-interrupt based single-character// transmission.#if CYGINT_IO_SERIAL_BLOCK_TRANSFERstatic rcv_req_reply_tserial_data_rcv_req(serial_channel *chan, int avail,                     int* space_avail, unsigned char** space){    cbuf_t *cbuf = &chan->in_cbuf;    int gap;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    // When there is software flow-control, force the serial device    // driver to use the single-char xmt/rcv functions, since these    // have to make policy decision based on the data. Rcv function    // may also have to transmit data to throttle the xmitter.    if (chan->config.flags & (CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_XONXOFF_RX))        return CYG_RCV_DISABLED;#endif    CYG_ASSERT(false == cbuf->block_mode_xfer_running,               "Attempting new block transfer while another is running");    // Check for space    gap = cbuf->nb;    if (gap == cbuf->len)        return CYG_RCV_FULL;#ifdef CYGDBG_USE_ASSERTS    cbuf->block_mode_xfer_running = true;#endif    if (0 == gap) {        // Buffer is empty. Reset put/get indexes to get max transfer in        // one chunk.        cbuf->get = 0;        cbuf->put = 0;        gap = cbuf->len;    } else {        // Free space (G = get, P = put, x = data, . = empty)        //  positive: xxxxP.....Gxxx        //  negative: ..GxxxxxP.....        [offer last chunk only]        // First try for a gap between put and get locations        gap = cbuf->get - cbuf->put;        if (gap < 0) {            // If failed, the gap is between put and the end of buffer            gap = cbuf->len - cbuf->put;        }    }    if (avail < gap) gap = avail;   // bound by what's available from hw        *space_avail = gap;    *space = &cbuf->data[cbuf->put];    CYG_ASSERT((gap+cbuf->nb) <= cbuf->len, "Buffer will overflow");    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");    return CYG_RCV_OK;}static voidserial_data_rcv_done(serial_channel *chan, int chars_rcvd){    cbuf_t *cbuf = &chan->in_cbuf;    cbuf->put += chars_rcvd;    cbuf->nb += chars_rcvd;    if (cbuf->put == cbuf->len) cbuf->put = 0;    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");    if (cbuf->waiting) {        cbuf->waiting = false;        cyg_drv_cond_broadcast(&cbuf->wait);    }#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL    // If we've hit the high water mark, tell the other side to stop    if ( cbuf->nb >= cbuf->high_water ) {        throttle_rx( chan, false );    }#endif#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT    // Wake up any pending selectors if we have    // put some data into a previously empty buffer.    if (chars_rcvd == cbuf->nb)        cyg_selwakeup( &cbuf->selinfo );#endif#ifdef CYGDBG_USE_ASSERTS    cbuf->block_mode_xfer_running = false;#endif}static xmt_req_reply_tserial_data_xmt_req(serial_channel *chan, int space,                    int* chars_avail, unsigned char** chars){    cbuf_t *cbuf = &chan->out_cbuf;    int avail;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    // When there is software flow-control, force the serial device    // driver to use the single-char xmt/rcv functions, since these    // have to make policy decision based on the data. Rcv function    // may also have to transmit data to throttle the xmitter.    if (chan->config.flags & (CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_XONXOFF_RX))        return CYG_XMT_DISABLED;#endif    CYG_ASSERT(false == cbuf->block_mode_xfer_running,               "Attempting new block transfer while another is running");#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL    // if we're meant to be throttled, just stop and leave    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {        (chan->funs->stop_xmit)(chan);  // Stop transmitting for now        return CYG_XMT_EMPTY;    }#endif    // Available data (G = get, P = put, x = data, . = empty)    //  0:        no data    //  negative: xxxxP.....Gxxx        [offer last chunk only]    //  positive: ..GxxxxxP.....    if (0 == cbuf->nb)        return CYG_XMT_EMPTY;#ifdef CYGDBG_USE_ASSERTS    cbuf->block_mode_xfer_running = true;#endif    if (cbuf->get >= cbuf->put) {        avail = cbuf->len - cbuf->get;    } else {        avail = cbuf->put - cbuf->get;    }    if (avail > space) avail = space;   // bound by space in hardware        *chars_avail = avail;    *chars = &cbuf->data[cbuf->get];    CYG_ASSERT(avail <= cbuf->len, "Avail overflow");    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");    return CYG_XMT_OK;}static voidserial_data_xmt_done(serial_channel *chan, int chars_sent){    cbuf_t *cbuf = &chan->out_cbuf;    serial_funs *funs = chan->funs;    int space;    cbuf->get += chars_sent;    cbuf->nb -= chars_sent;    if (cbuf->get == cbuf->len) cbuf->get = 0;    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");    CYG_ASSERT(cbuf->nb >= 0, "Buffer underflow");    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");    if (0 == cbuf->nb) {        (funs->stop_xmit)(chan);  // Done with transmit        cbuf->get = cbuf->put = 0; // reset ptrs if empty    }    // See if there is now enough room to restart writer    space = cbuf->len - cbuf->nb;    if (space >= cbuf->low_water) {        if (cbuf->waiting) {            cbuf->waiting = false;            cyg_drv_cond_broadcast(&cbuf->wait);        }#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT        cyg_selwakeup( &cbuf->selinfo );#endif                        }#ifdef CYGDBG_USE_ASSERTS    cbuf->block_mode_xfer_running = false;#endif}#endif // CYGINT_IO_SERIAL_BLOCK_TRANSFER// ---------------------------------------------------------------------------// EOF serial.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -