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

📄 can.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      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 + -