/* =================================================================
 *
 *      test_mods2.c
 *
 *      Test program for the object loader. This version uses the
 *      memory loader rather than the filesystem.
 *
 * ================================================================= 
 * ####ECOSGPLCOPYRIGHTBEGIN####                                     
 * -------------------------------------------                       
 * This file is part of eCos, the Embedded Configurable Operating System.
 * Copyright (C) 2005, 2008 Free Software Foundation, Inc.           
 * Copyright (C) 2005, 2008 eCosCentric Limited                      
 *
 * 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):    nickg, Anthony Tonizzo (atonizzo@gmail.com)
 *  Date:         2005-05-13
 *  Purpose:      
 *  Description:  
 *               
 * ####DESCRIPTIONEND####
 * 
 * =================================================================
 */

#include <pkgconf/system.h>
#include <cyg/kernel/kapi.h>    // Kernel API.
#include <cyg/infra/diag.h>     // For diagnostic printing.
#include <cyg/infra/testcase.h>

#include CYGHWR_MEMORY_LAYOUT_H

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>

#include <cyg/objloader/objload.h>

//==========================================================================
// Test data. Two example data files are generated so that
// the test will work on both big-endian and little-endian targets.

#if (CYG_BYTEORDER == CYG_LSBFIRST)
# include <cyg/objloader/hello_le.h>
#else
# include <cyg/objloader/hello_be.h>
#endif

//==========================================================================

#if CYGMEM_REGION_ram_SIZE > (64*1024)
#define THREAD_STACK_SIZE   8192
#else
#define THREAD_STACK_SIZE   1024
#endif

#define THREAD_PRIORITY     12

cyg_uint8 thread_a_stack[THREAD_STACK_SIZE] __attribute__((__aligned__ (16)));
cyg_uint8 thread_b_stack[THREAD_STACK_SIZE] __attribute__((__aligned__ (16)));

cyg_thread thread_a_obj;
cyg_thread thread_b_obj;
cyg_handle_t thread_a_hdl;
cyg_handle_t thread_b_hdl;

#define SHOW_RESULT(_fn, _res) \
diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");

int weak_fn_called = 0;

void (*thread_a)(cyg_addrword_t);
void (*thread_b)(cyg_addrword_t);

//==========================================================================

void weak_function(void)
{
  CYG_TEST_PASS("Applications weak function called");
  weak_fn_called++;
}

//==========================================================================
// This is the main starting point for our example application.

void cyg_user_start(void)
{
    void* lib_handle;
    void (*fn)(void);
    
    CYG_TEST_INIT();

    CYG_TEST_INFO("Object loader module test started");

    lib_handle = cyg_ldr_open(CYG_LDR_MEMORY, (CYG_ADDRWORD)__filedata);
    CYG_TEST_CHECK(lib_handle , "Unable to open object file to load");

    fn = cyg_ldr_find_symbol(lib_handle, "print_message");
    CYG_TEST_CHECK(fn , "Unable to find print_message function");

    fn();

    fn = cyg_ldr_find_symbol(lib_handle, "weak_function");
    CYG_TEST_CHECK(fn , "Unable to find weak_function");
    
    fn();

    fn = cyg_ldr_find_symbol (lib_handle, "unresolvable_symbol");
    CYG_TEST_CHECK(!fn , "Found none existing symbol!");
    
    thread_a = cyg_ldr_find_symbol(lib_handle, "thread_a");
    thread_b = cyg_ldr_find_symbol(lib_handle, "thread_b");
    CYG_TEST_CHECK(thread_a && thread_b , "Unable to find thread functions");
    
    // Create our two threads.
    cyg_thread_create(THREAD_PRIORITY,
                       thread_a,
                       (cyg_addrword_t) 75,
                       "Thread A",
                       (void *)thread_a_stack,
                       THREAD_STACK_SIZE,
                       &thread_a_hdl,
                       &thread_a_obj);

    cyg_thread_create(THREAD_PRIORITY + 1,
                       thread_b,
                       (cyg_addrword_t) 68,
                       "Thread B",
                       (void *)thread_b_stack,
                       THREAD_STACK_SIZE,
                       &thread_b_hdl,
                       &thread_b_obj);

    // Resume the threads so they start when the scheduler begins.
    cyg_thread_resume(thread_a_hdl);
    cyg_thread_resume(thread_b_hdl);

    cyg_scheduler_start();
}

// -----------------------------------------------------------------------------
// External symbols.
// -----------------------------------------------------------------------------

#if CYGMEM_REGION_ram_SIZE > (64*1024)

CYG_LDR_TABLE_KAPI_ALARM()
CYG_LDR_TABLE_KAPI_CLOCK()
CYG_LDR_TABLE_KAPI_COND()
CYG_LDR_TABLE_KAPI_COUNTER()
CYG_LDR_TABLE_KAPI_EXCEPTIONS()
CYG_LDR_TABLE_KAPI_FLAG()
CYG_LDR_TABLE_KAPI_INTERRUPTS()
CYG_LDR_TABLE_KAPI_MBOX()
CYG_LDR_TABLE_KAPI_MEMPOOL_FIX()
CYG_LDR_TABLE_KAPI_MEMPOOL_VAR()
CYG_LDR_TABLE_KAPI_MUTEX()
CYG_LDR_TABLE_KAPI_SCHEDULER()
CYG_LDR_TABLE_KAPI_SEMAPHORE()
CYG_LDR_TABLE_KAPI_THREAD()
//CYG_LDR_TABLE_STRING()
//CYG_LDR_TABLE_STDIO()
CYG_LDR_TABLE_INFRA_DIAG()
//CYG_LDR_TABLE_FILEIO()

#else

CYG_LDR_TABLE_FUN( diag_printf );
CYG_LDR_TABLE_FUN( cyg_semaphore_init );
CYG_LDR_TABLE_FUN( cyg_semaphore_wait );
CYG_LDR_TABLE_FUN( cyg_semaphore_post );
CYG_LDR_TABLE_FUN( cyg_thread_delay );

#endif

//==========================================================================

// Test case infrastructure functions
CYG_LDR_TABLE_FUN(cyg_test_output);
CYG_LDR_TABLE_FUN(cyg_test_exit);

// Test function
CYG_LDR_TABLE_FUN(weak_function);

// Test Variable
CYG_LDR_TABLE_VAR(weak_fn_called);

//==========================================================================
