📄 can.c
字号:
{
pbuf_info->tx_count = 0;
}
}
break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
//
// return current timeouts
//
case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
{
cyg_can_timeout_info_t *ptimeout_info;
if (*len < sizeof(cyg_can_timeout_info_t))
{
return -EINVAL;
}
*len = sizeof(cyg_can_timeout_info_t);
ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
ptimeout_info->rx_timeout = in_cbuf->timeout;
ptimeout_info->tx_timeout = out_cbuf->timeout;
}
break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
//
// check if blocking calls are enabled
//
case CYG_IO_GET_CONFIG_READ_BLOCKING:
{
if (*len < sizeof(cyg_uint32))
{
return -EINVAL;
}
*(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
}
break;
//
// check if nonblocking calls are enabled
//
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_CAN_SUPPORT_NONBLOCKING
//
// return hardware description interface
//
case CYG_IO_GET_CONFIG_CAN_HDI :
{
cyg_can_hdi *hdi = (cyg_can_hdi *)xbuf;
if (*len != sizeof(cyg_can_hdi))
{
return -EINVAL;
}
hdi = hdi; // avoid compiler warnings
*len = sizeof(cyg_can_hdi);
//
// pass down to low level to gather more information about
// CAN hardware
//
res = (funs->get_config)(chan, key, xbuf, len);
}
break;
default:
res = (funs->get_config)(chan, key, xbuf, len);
} // switch (key)
return res;
}
//===========================================================================
// Set CAN channel configuration
//===========================================================================
static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
cyg_uint32 key,
const void *xbuf,
cyg_uint32 *len)
{
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
can_channel *chan = (can_channel *)t->priv;
Cyg_ErrNo res = ENOERR;
can_lowlevel_funs *funs = chan->funs;
can_cbuf_t *out_cbuf = &chan->out_cbuf;
can_cbuf_t *in_cbuf = &chan->in_cbuf;
switch (key)
{
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
//
// Set calls to read function to blocking / nonblocking mode
//
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;
//
// set calls to write functions to blocking / nonblocking mode
//
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_CAN_SUPPORT_NONBLOCKING
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
//
// return current timeouts
//
case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
{
cyg_can_timeout_info_t *ptimeout_info;
if (*len < sizeof(cyg_can_timeout_info_t))
{
return -EINVAL;
}
*len = sizeof(cyg_can_timeout_info_t);
ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
in_cbuf->timeout = ptimeout_info->rx_timeout;
out_cbuf->timeout = ptimeout_info->tx_timeout;
}
break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
case CYG_IO_SET_CONFIG_CAN_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->data_cnt = 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_CAN_INPUT_FLUSH,
NULL, NULL);
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&in_cbuf->lock);
} // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
//
// flush any buffered output
//
case CYG_IO_SET_CONFIG_CAN_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->data_cnt > 0)
{
out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 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_CAN_OUTPUT_FLUSH,
NULL, NULL);
if (out_cbuf->waiting)
{
out_cbuf->abort = true;
cyg_drv_cond_broadcast(&out_cbuf->wait);
out_cbuf->waiting = false;
}// if (out_cbuf->waiting)
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&out_cbuf->lock);
}
break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH:
//
// wait until all messages in outbut buffer are sent
//
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->data_cnt > 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;// CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
//
// Abort any outstanding I/O, including blocked reads
// Caution - assumed to be called from 'timeout' (i.e. DSR) code
//
case CYG_IO_SET_CONFIG_CAN_ABORT :
{
in_cbuf->abort = true;
cyg_drv_cond_broadcast(&in_cbuf->wait);
out_cbuf->abort = true;
cyg_drv_cond_broadcast(&out_cbuf->wait);
}
break;
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
//
// Set callback configuration
// To disable callback set flag_mask = 0
//
case CYG_IO_SET_CONFIG_CAN_CALLBACK:
{
if (*len != sizeof(cyg_can_callback_cfg))
{
return -EINVAL;
}
// Copy data under DSR locking
cyg_drv_dsr_lock();
chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf);
cyg_drv_dsr_unlock();
}
break;
#endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK
default:
//
// pass down to lower layers
//
res = (funs->set_config)(chan, key, xbuf, len);
} // switch (key)
return res;
}
//===========================================================================
// Select support for CAN channel
//===========================================================================
static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
{
//
// do nothing here because we currently do not support select
//
return true;
}
//===========================================================================
// Callback for received events
//===========================================================================
static void can_rcv_event(can_channel *chan, void *pdata)
{
can_cbuf_t *cbuf = &chan->in_cbuf;
CYG_CAN_EVENT_T *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
cyg_uint16 flags;
#endif
//
// cbuf is a ring buffer - if the buffer is full, then we overwrite the
// oldest message in buffer so the user will always get the actual and
// last state of the external hardware that is connected to the
// CAN bus. We need to call cyg_drv_dsr_lock() here because this function
// may be called from different message box interrupts and so we have to
// protect data access here
//
cyg_drv_dsr_lock();
prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event
if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
{
if (cbuf->data_cnt < cbuf->len)
{
cbuf->data_cnt++;
}
else
{
//
// the buffer is full but a new message arrived. We store this new
// message and overwrite the oldest one, but at least we tell the user
// that there is an overrun in RX queue
//
prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
cbuf->get = (cbuf->get + 1) % cbuf->len;
}
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
flags = prxbuf[cbuf->put].flags;
#endif
cbuf->put = (cbuf->put + 1) % cbuf->len;
if (cbuf->waiting)
{
cbuf->waiting = false;
cyg_drv_cond_broadcast(&cbuf->wait);
}
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
// Call application callback function, if any of the flag events
// are unmasked.
if((flags & chan->callback_cfg.flag_mask) &&
(chan->callback_cfg.callback_func))
{
chan->callback_cfg.callback_func(flags,
chan->callback_cfg.data);
}
#endif
}
cyg_drv_dsr_unlock();
}
//===========================================================================
// Callback function for transmit events
//===========================================================================
static void can_xmt_msg(can_channel *chan, void *pdata)
{
can_cbuf_t *cbuf = &chan->out_cbuf;
can_lowlevel_funs *funs = chan->funs;
CYG_CAN_MSG_T *ptxbuf = (CYG_CAN_MSG_T *)cbuf->pdata;
CYG_CAN_MSG_T *pbuf_txmsg;
//
// transmit messages as long as there are messages in the buffer
//
while (cbuf->data_cnt > 0)
{
pbuf_txmsg = &ptxbuf[cbuf->get];
if (funs->putmsg(chan, pbuf_txmsg, pdata))
{
cbuf->get = (cbuf->get + 1) % cbuf->len;
cbuf->data_cnt--;
}
else
{
//
// we are here because the hardware is busy at the moment and
// we can't send another message - now we check if there is already
// some space in buffer so we can wakeup the writer
//
if ((cbuf->len - cbuf->data_cnt) > 0)
{
if (cbuf->waiting)
{
cbuf->waiting = false;
cyg_drv_cond_broadcast(&cbuf->wait);
}
}
return;
}
} // while (cbuf->data_cnt > 0)
funs->stop_xmit(chan); // Done with transmit
if (cbuf->waiting)
{
cbuf->waiting = false;
cyg_drv_cond_broadcast(&cbuf->wait);
}
}
//---------------------------------------------------------------------------
// end of can.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -