view packages/devs/can/arm/lpc2xxx/current/tests/can_multichan_rx.c @ 2509:a52d470bc691

* cdl/can_lpc2xxx.cdl: Added CYGOPT_DEVS_CAN_LPC2XXX_ALIE to make arbitration lost interrupt optional. Added option CYGNUM_DEVS_CAN_LPC2XXX_INT_PRIORITY to configure the interrupt priority for global CAN interrupt in LPC24xx variants. * include/can_lpc2xxx_baudrates.h: Replaced CYGNUM_CAN_LPC2XXX_VPB_CLK by CYGNUM_HAL_ARM_LPC2XXX_CAN_CLK because newer variants like LPC24xx do not have a global VPB_CLK. * src/can_accfilt_lpc2xxx.c: Adjusted LPC2XXX_CAN_FIRST_IN_LUT to be 0 for LPC24xxx variants. Added macro CAN_CHAN_NO_LUT(_info_) to abstract channel numbering from acceptance filter code. * src/can_lpc2xxx.c: Removed icr data field from lpc2xxx_can_info_st structure because it is not required any longer. A lot of small modifications to make the driver usable with newer LPC2xxx variants like LPC24xx. ISR and DSR code changed - instead of disabling interrupts in IER register they are disabled in VIC by using cyg_drv_interrupt_mask() function calls. Added global CAN ISR and DSR for LPC24xx variants (they do not support individual interrupt vectors for RX and TX interrupts). Moved LUT error checking code from ISR into DSR to keep ISR as short as possible and made LUT error checking code optional. * cdl/can_lpc2xxx.cdl: add CAN interrupt priorities * src/can_lpc2xxx.c: add CAN interrupt priorities, repair "chan" definition missing in rx_ISR * src/can_accfilt_lpc2xxx.c: add various types of CAN controllers numbering (depends on LPC2XXX version)
author asl
date Tue, 22 Jul 2008 19:40:02 +0000
parents 641c0b821739
children 74dbf4c3f2e1
line wrap: on
line source

//==========================================================================
//
//        can_multichan_rx.c
//
//        CAN RX test for multiple CAN channels
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// 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:          2007-06-26
// Description:   CAN RX test for multiple CAN controller channels
//####DESCRIPTIONEND####


//===========================================================================
//                                INCLUDES
//===========================================================================
#include <pkgconf/system.h>

#include <cyg/infra/testcase.h>         // test macros
#include <cyg/infra/cyg_ass.h>          // assertion macros
#include <cyg/infra/diag.h>

// Package requirements
#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL)

#include <pkgconf/kernel.h>
#include <cyg/io/io.h>
#include <cyg/io/canio.h>


// Package option requirements
#if defined(CYGFUN_KERNEL_API_C)

#include <cyg/hal/hal_arch.h>           // CYGNUM_HAL_STACK_SIZE_TYPICAL
#include <cyg/kernel/kapi.h>

// Package option requirements
#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)

#include "can_test_aux.inl" // include CAN test auxiliary functions
//===========================================================================
//                               DATA TYPES
//===========================================================================
typedef struct st_thread_data
{
    cyg_thread   obj;
    long         stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
    cyg_handle_t hdl;
} thread_data_t;


//===========================================================================
//                              LOCAL DATA
//===========================================================================
cyg_thread_entry_t can_thread;
thread_data_t      can0_thread_data;
cyg_io_handle_t    hCAN_Tbl[4];


//===========================================================================
// Setup acceptance filter
//===========================================================================
void can_setup_channel(cyg_io_handle_t hCAN, unsigned char Channel)
{
    cyg_uint32              len;
    cyg_can_msgbuf_cfg      msgbox_cfg;
    cyg_uint8               i;
    cyg_uint32              blocking;
    
    //
    // First we reset message buffer configuration - this is mandatory bevore starting
    // message buffer runtime configuration. This call clears/frees all message buffers
    // The CAN controller cannot receive any further CAN message after this call
    //
    msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;
    len = sizeof(msgbox_cfg);
    if (ENOERR != cyg_io_set_config(hCAN, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len))
    {
        CYG_TEST_FAIL_FINISH("Error resetting message buffer configuration of /dev/can0");
    } 
    
    //
    // Now setup 10 message filters for this channel
    //
    for (i = 0; i < 10; ++i)
    {
        cyg_can_filter rx_filter;    
        
        rx_filter.cfg_id  = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD;
        rx_filter.msg.id  = Channel * 0x100 + i;
        rx_filter.msg.ext = CYGNUM_CAN_ID_STD;
  
        len = sizeof(rx_filter); 
        if (ENOERR != cyg_io_set_config(hCAN, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rx_filter, &len))
        {
            CYG_TEST_FAIL_FINISH("Error writing config");
        }
        else if (CYGNUM_CAN_MSGBUF_NA == rx_filter.handle)
        {
            CYG_TEST_FAIL_FINISH("Error setting up message filter");
        }        
    }
    
    //
    // Now set driver into nonblocking mode because the receiver thread will
    // receive the messages from all channels
    //
    blocking = 0;
    len = sizeof(blocking);
    if (ENOERR != cyg_io_set_config(hCAN, CYG_IO_SET_CONFIG_READ_BLOCKING ,&blocking, &len))
    {
        CYG_TEST_FAIL_FINISH("Error setting channel into nonblocking mode");
    } 
    
    //
    // If timeouts are supported we need to setup a timeout value of 0 because
    // the driver should return immediatelly if no message is available
    //
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
    cyg_can_timeout_info_t timeouts;
    
    timeouts.rx_timeout = 0;
    timeouts.tx_timeout = 0;
    len = sizeof(timeouts);
    if (ENOERR != cyg_io_set_config(hCAN, CYG_IO_SET_CONFIG_CAN_TIMEOUT ,&timeouts, &len))
    {
        CYG_TEST_FAIL_FINISH("Error setting timeout for channel");
    } 
#endif
}


//===========================================================================
//                             READER THREAD 
//===========================================================================
void can_thread(cyg_addrword_t data)
{
    cyg_uint32              len;
    cyg_uint8               i = 0;

    //
    // Check that all cannels have the same baudrate
    //
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0
    can_setup_channel(hCAN_Tbl[0], 0);
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1
    can_setup_channel(hCAN_Tbl[1], 1);
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2
    can_setup_channel(hCAN_Tbl[2], 2);
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3
    can_setup_channel(hCAN_Tbl[3], 3);
#endif
    
    diag_printf("\n\nThis test uses all available CAN channels for reception\n"
                "of CAN standard messages. The following messages will be received:\n\n");
    
    for (i = 0; i < 4; ++i)
    {
        if (hCAN_Tbl[i])
        {
            diag_printf("CAN channel %d: msg: 0x%03x - 0x%03x\n", i, i * 0x100, i * 0x100 + 9);
        }
    }
    
    diag_printf("\n\nYou can stop this test by sending a message with ID 0xX09\n");
    
    while (1)
    {
        for (i = 0; i < 4; ++i)
        {
            if (hCAN_Tbl[i])
            {
                Cyg_ErrNo     ret;
                cyg_can_event rx_event; 
                
                len = sizeof(rx_event);
                ret = cyg_io_read(hCAN_Tbl[i], &rx_event, &len);
                if ((ret == -EAGAIN) || (ret == -EINTR))
                {
                    continue;    
                }
                
                if (ENOERR != ret)
                {
                    CYG_TEST_FAIL_FINISH("Error reading from channel");
                }
                else
                {
                    diag_printf("Channel %d events: ", i);
                    print_can_flags(rx_event.flags, "");
                    if (rx_event.flags & CYGNUM_CAN_EVENT_RX)
                    {
                        print_can_msg(&rx_event.msg, "");
                        if ((rx_event.msg.id & 9) == 9)
                        {
                            CYG_TEST_PASS_FINISH("LPC2xxx CAN multi channel RX test OK");    
                        }
                    } // if (rx_event.flags & CYGNUM_CAN_EVENT_RX)
                }
            } // if (hCAN_Tbl[i])
        } // for (i = 0; i < 4; ++i)
    } // while (1)
}



void
cyg_start(void)
{
    CYG_TEST_INIT();

#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0
    //
    // open CAN device driver
    //
    if (ENOERR != cyg_io_lookup(CYGPKG_DEVS_CAN_LPC2XXX_CAN0_NAME, &hCAN_Tbl[0])) 
    {
        CYG_TEST_FAIL_FINISH("Error opening CAN channel 0");
    }
#else
    hCAN_Tbl[0] = 0;  
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1
    //
    // open CAN device driver
    //
    if (ENOERR != cyg_io_lookup(CYGPKG_DEVS_CAN_LPC2XXX_CAN1_NAME, &hCAN_Tbl[1])) 
    {
        CYG_TEST_FAIL_FINISH("Error opening CAN channel 1");
    }
#else
    hCAN_Tbl[1] = 0;  
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2
    //
    // open CAN device driver
    //
    if (ENOERR != cyg_io_lookup(CYGPKG_DEVS_CAN_LPC2XXX_CAN2_NAME, &hCAN_Tbl[2])) 
    {
        CYG_TEST_FAIL_FINISH("Error opening CAN channel 2");
    }
#else
    hCAN_Tbl[2] = 0;  
#endif
    
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3
    //
    // open CAN device driver
    //
    if (ENOERR != cyg_io_lookup(CYGPKG_DEVS_CAN_LPC2XXX_CAN3_NAME, &hCAN_Tbl[3])) 
    {
        CYG_TEST_FAIL_FINISH("Error opening CAN channel 3");
    }
#else
    hCAN_Tbl[3] = 0;  
#endif
    
    //
    // create the thread that accesses the CAN device driver
    //
    cyg_thread_create(4, can_thread, 
                        (cyg_addrword_t) 0,
                        "can0_thread", 
                        (void *) can0_thread_data.stack, 
                        1024 * sizeof(long),
                        &can0_thread_data.hdl, 
                        &can0_thread_data.obj);
                        
    cyg_thread_resume(can0_thread_data.hdl);
    
    cyg_scheduler_start();
}
#else // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
#define N_A_MSG "Needs support for nonblocking calls"
#endif

#else // CYGFUN_KERNEL_API_C
#define N_A_MSG "Needs kernel C API"
#endif

#else // CYGPKG_IO_CAN && CYGPKG_KERNEL
#define N_A_MSG "Needs Kernel"
#endif

#ifdef N_A_MSG
void
cyg_start( void )
{
    CYG_TEST_INIT();
    CYG_TEST_NA(N_A_MSG);
}
#endif // N_A_MSG

//---------------------------------------------------------------------------
// EOF can_multichan_rx.c