//==========================================================================
//
//        flexcan_wake.c
//
//        FlexCAN wake test
//
//==========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, 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.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):     Uwe Kindler
// Contributors:  Uwe Kindler
// Date:          2005-09-10
// Description:   FlexCAN test of standby and wake
//####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>


//===========================================================================
//                               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 can0_thread;
thread_data_t      can0_thread_data;


cyg_io_handle_t    hDrvFlexCAN;


//===========================================================================
//                          LOCAL FUNCTIONS
//===========================================================================
#include "can_test_aux.inl" // include CAN test auxiliary functions


//===========================================================================
//                             READER THREAD 
//===========================================================================
void can0_thread(cyg_addrword_t data)
{
    cyg_uint32             len;
    cyg_can_event          rx_event1;
    cyg_can_event          rx_event2;
    cyg_can_msgbuf_info    msgbox_info;
    cyg_can_mode           mode; 
    cyg_can_state          state;
    
   
    diag_printf("Test of FlexCAN standby mode with selfwakeup\n"
                "As soon as a message arrives the FlexCAN modul\n"
                "will leave standby and generates a leave standby event.\n"
                "Each time you send a message you should see LSTY first\n"
                "for \"leaving standby\" and then \"RX\" for the\n"
                "RX event that caused the leave standby event. You can send\n"
                "a CAN data frame with any ID\n");
                
    diag_printf("!!! This test can be stopped by sending a data frame with ID 0x100 !!!\n\n");
    
    len = sizeof(msgbox_info);
    if (ENOERR != cyg_io_get_config(hDrvFlexCAN, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len))
    {
        CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0");
    } 
    else
    {
        diag_printf("Message boxes available: %d    free: %d\n", 
                    msgbox_info.count, msgbox_info.free);
    }
    
    while (1)
    {
       //
       // now we set FlexCAN into standby mode
       //
       mode = CYGNUM_CAN_MODE_STANDBY;
       len = sizeof(mode);
       if (ENOERR != cyg_io_set_config(hDrvFlexCAN, CYG_IO_SET_CONFIG_CAN_MODE ,&mode, &len))
       {
           CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0");
       } 
    
       //
       // now check if FlexCAN modul is really in standby mode
       //
       len = sizeof(state);
       if (ENOERR != cyg_io_get_config(hDrvFlexCAN, CYG_IO_GET_CONFIG_CAN_STATE ,&state, &len))
       {
           CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0");
       } 
    
   
       if (state != CYGNUM_CAN_STATE_STANDBY)
       {
           CYG_TEST_FAIL_FINISH("Error stopping FlexCAN /dev/can0");
       }
       
       //
       // as soon as a message arrives the FlexCAN modul leaves standby mode
       // and we should receive a CYGNUM_CAN_EVENT_LEAVING_STANDBY event but
       // we will also receive a RX event because a message arrived
       // 
       len = sizeof(rx_event1);      
       if (ENOERR != cyg_io_read(hDrvFlexCAN, &rx_event1, &len))
       {
           CYG_TEST_FAIL_FINISH("Error reading from /dev/can0");
       }
       
       len = sizeof(rx_event2);      
       if (ENOERR != cyg_io_read(hDrvFlexCAN, &rx_event2, &len))
       {
           CYG_TEST_FAIL_FINISH("Error reading from /dev/can0");
       }
       
       print_can_flags(rx_event1.flags, "");
       print_can_flags(rx_event2.flags, "");
       
       //
       // The first event we receive should be a leaving standby event because
       // first flexcan leaves standby and then a message will be received
       // 
       if (!(rx_event1.flags & CYGNUM_CAN_EVENT_LEAVING_STANDBY))
       {
           CYG_TEST_FAIL_FINISH("CYGNUM_CAN_EVENT_LEAVING_STANDBY event expexted /dev/can0");
       }
       
       if (rx_event2.msg.id == 0x100)
       {
           CYG_TEST_PASS_FINISH("flexcan_wake test OK");
       }
    }              
}


void
cyg_start(void)
{
    CYG_TEST_INIT();
    
    //
    // open flexcan device driver
    //
    if (ENOERR != cyg_io_lookup("/dev/can0", &hDrvFlexCAN)) 
    {
        CYG_TEST_FAIL_FINISH("Error opening /dev/can0");
    }
    
   
    //
    // create the two threads which access the CAN device driver
    // a reader thread with a higher priority and a writer thread
    // with a lower priority
    //
    cyg_thread_create(4, can0_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 // CYGFUN_KERNEL_API_C
#define N_A_MSG "Needs kernel C API"
#endif

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

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

// EOF flexcan_wake.c
