📄 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_boolserial_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 + -