📄 can.c
字号:
//==========================================================================
//
// io/can/common/can.c
//
// High level CAN driver
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): Uwe Kindler
// Contributors: Uwe Kindler
// Date: 2005-05-12
// Purpose: Top level CAN driver
// Description:
//
//####DESCRIPTIONEND####
//
//==========================================================================
//==========================================================================
// INCLUDES
//==========================================================================
#include <pkgconf/io.h>
#include <pkgconf/io_can.h>
#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#include <cyg/io/can.h>
#include <cyg/infra/cyg_ass.h> // assertion support
#include <cyg/infra/diag.h> // diagnostic output
//==========================================================================
// MACROS
//==========================================================================
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
#define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time))
#else
#define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond)
#endif
//==========================================================================
// LOCAL FUNCTIONS
//==========================================================================
//
// Device I/O functions
//
static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len);
static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len);
static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len);
static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len);
//
// Callback functions into upper layer driver
//
static void can_init(can_channel *chan);
static void can_rcv_event(can_channel *chan, void *pdata);
static void can_xmt_msg(can_channel *chan, void *pdata);
//
// Device I/O table
//
DEVIO_TABLE(cyg_io_can_devio,
can_write,
can_read,
can_select,
can_get_config,
can_set_config
);
//
// Callbacks into upper layer driver
//
CAN_CALLBACKS(cyg_io_can_callbacks,
can_init,
can_xmt_msg,
can_rcv_event);
//===========================================================================
// Initialize CAN driver
//===========================================================================
static void can_init(can_channel *chan)
{
can_cbuf_t *cbuf;
if (chan->init)
{
return;
}
cbuf = &chan->in_cbuf;
cbuf->waiting = false;
cbuf->abort = false;
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
cbuf->blocking = true;
#endif
cyg_drv_mutex_init(&cbuf->lock);
cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
cbuf = &chan->out_cbuf;
cbuf->waiting = false;
cbuf->abort = false;
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
cbuf->blocking = true;
#endif
cyg_drv_mutex_init(&cbuf->lock);
cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
chan->init = true;
}
//===========================================================================
// Write exactly one CAN message to CAN bus
//===========================================================================
static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
{
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
can_channel *chan = (can_channel *)t->priv;
can_lowlevel_funs *funs = chan->funs;
Cyg_ErrNo res = ENOERR;
can_cbuf_t *cbuf = &chan->out_cbuf;
cyg_uint32 size = *len;
//
// the user need to provide a can message buffer
//
if (*len != sizeof(cyg_can_message))
{
return -EINVAL;
}
cyg_drv_mutex_lock(&cbuf->lock);
cbuf->abort = false;
cyg_drv_dsr_lock(); // avoid race condition while testing pointers
while (size > 0)
{
if (cbuf->data_cnt == cbuf->len)
{
cbuf->waiting = true; // Buffer full - wait for space
funs->start_xmit(chan); // Make sure xmit is running
//
// Check flag: 'start_xmit' may have obviated the need
// to wait
//
if (cbuf->waiting)
{
cbuf->pending += size; // Have this much more to send [eventually]
#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
//
// If timeouts are enabled and we use nonblocking calls then we
// can use the timeout values
//
if (!cbuf->blocking)
{
if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
{
cbuf->abort = true;
}
} // if (!cbuf->blocking)#
else
#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
//
// if this is a nonblocking call then we return immediatelly
//
if (!cbuf->blocking)
{
*len = 0;
res = -EAGAIN;
break;
}
else
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
#endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
{
if(!cyg_drv_cond_wait(&cbuf->wait))
{
cbuf->abort = true;
}
}
cbuf->pending -= size;
if (cbuf->abort)
{
// Give up!
*len -= size; // number of characters actually sent
cbuf->abort = false;
cbuf->waiting = false;
res = -EINTR;
break;
} // if (cbuf->abort)
} // if (cbuf->waiting)
} // if (cbuf->data_cnt == cbuf->len)
else
{
//
// there is enougth space left so we can store additional data
//
CYG_CAN_MSG_T *ptxbuf = (CYG_CAN_MSG_T *)cbuf->pdata;
CYG_CAN_MSG_T *pbuf_message = &ptxbuf[cbuf->put];
cyg_can_message *pmessage = (cyg_can_message *)_buf;
CYG_CAN_WRITE_MSG(pbuf_message, pmessage); // copy message
cbuf->put = (cbuf->put + 1) % cbuf->len;
cbuf->data_cnt++;
size -= sizeof(cyg_can_message);
}
} // while (size > 0)
(funs->start_xmit)(chan); // Start output as necessary
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&cbuf->lock);
return res;
}
//===========================================================================
// Read one single CAN event from hw
//===========================================================================
static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
{
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
can_channel *chan = (can_channel *)t->priv;
can_cbuf_t *cbuf = &chan->in_cbuf;
cyg_uint32 size = 0;
Cyg_ErrNo res = ENOERR;
//
// the user need to provide a can event buffer
//
if (*len != sizeof(cyg_can_event))
{
return -EINVAL;
}
cyg_drv_mutex_lock(&cbuf->lock);
cbuf->abort = false;
cyg_drv_dsr_lock(); // avoid race conditions
while (size < *len)
{
//
// if message buffer contains at least one message then read the
// oldest message from buffer and return
//
if (cbuf->data_cnt > 0)
{
CYG_CAN_EVENT_T *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
CYG_CAN_EVENT_T *pbuf_event = &prxbuf[cbuf->get];
cyg_can_event *pevent = (cyg_can_event *)_buf;
CYG_CAN_READ_EVENT(pevent, pbuf_event); // copy event
cbuf->get = (cbuf->get + 1) % cbuf->len;
cbuf->data_cnt--;
size += sizeof(cyg_can_event);
}
else
{
//
// if messaeg buffer does not contain any message, then wait until
// a message arrives or return immediatelly if nonblocking calls are
// supported
//
cbuf->waiting = true;
#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
//
// If timeouts are enabled and we use nonblocking calls then we
// can use the timeout values
//
if (!cbuf->blocking)
{
if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
{
cbuf->abort = true;
}
} // if (!cbuf->blocking)#
else
#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
//
// if this is a nonblocking call then we return immediatelly
//
if (!cbuf->blocking)
{
*len = 0;
res = -EAGAIN;
break;
}
else
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
{
if(!cyg_drv_cond_wait(&cbuf->wait))
{
cbuf->abort = true;
}
}
if (cbuf->abort)
{
*len = size;
cbuf->abort = false;
cbuf->waiting = false;
res = -EINTR;
break;
}
}
} // while (size < *len)
cyg_drv_dsr_unlock();
cyg_drv_mutex_unlock(&cbuf->lock);
return res;
}
//===========================================================================
// Query CAN channel configuration data
//===========================================================================
static Cyg_ErrNo can_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;
can_channel *chan = (can_channel *)t->priv;
Cyg_ErrNo res = ENOERR;
cyg_can_info_t *pcan_info = (cyg_can_info_t *)xbuf;
can_cbuf_t *out_cbuf = &chan->out_cbuf;
can_cbuf_t *in_cbuf = &chan->in_cbuf;
can_lowlevel_funs *funs = chan->funs;
switch (key)
{
//
// query about CAN configuration like baud rate
//
case CYG_IO_GET_CONFIG_CAN_INFO :
if (*len < sizeof(cyg_can_info_t))
{
return -EINVAL;
}
*pcan_info = chan->config;
*len = sizeof(chan->config);
break;
//
// return rx/tx buffer sizes and counts
//
case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
{
cyg_can_buf_info_t *pbuf_info;
if (*len < sizeof(cyg_can_buf_info_t))
{
return -EINVAL;
}
*len = sizeof(cyg_can_buf_info_t);
pbuf_info = (cyg_can_buf_info_t *)xbuf;
pbuf_info->rx_bufsize = in_cbuf->len;
if (pbuf_info->rx_bufsize)
{
pbuf_info->rx_count = in_cbuf->data_cnt ;
}
else
{
pbuf_info->rx_count = 0;
}
pbuf_info->tx_bufsize = out_cbuf->len;
if (pbuf_info->tx_bufsize)
{
pbuf_info->tx_count = out_cbuf->data_cnt;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -