/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * =======================================================================
 * This file contains the code that starts ThreadX and the TCP/IP stack
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  =======================================================
 *	DXL	08/19/02	- file is broken up into constant.c, errhndlr.c, main.c security.c
 *					  Use API define for application configuration
 *  12-17-02  LZ    Moved the following code from startTcp.c. before calling dialog code.
 *                  GNU libc stdio routings call isatty() -- please refer to netos_serl.c
 *                       watchThisFileDescriptor ( "/com/0", 0);
 *                       watchThisFileDescriptor ( "/com/1", 1);
 *  05/16/03 JZW    Replaced c++-style comments with c-style comments
 *  06/02/03 JZW    include ind_io.h to get fp for ioctl
 *  06/25/03 JZW    Added typedefs to be used as typecasts in copying
 *                  our read/write functions into stdin/stdout...
 *  07/03/02 JZW    Add function prototype for filesystem_init
 *  04/11/05 JZW    Function setupTime now uses function NASNTPTimeInstall. This attempts
 *                  to start the sntp client using both primary and secondary sntp
 *                  servers
 *  10/21/05 JZW    in function setupTime, was using NAGetAppSntpSecondary to access
 *                  the secondary sntp server. This would only check appconf.h. By changing
 *                  to using NAGetSntpSecondaryServer, we check for a secondary server
 *                  in both the internal params structure AND if empty appconf.h
 *                  Vantive 17149
 *
 */

#include <stdio.h>
#include <string.h>
#include "powersave.h"

#ifdef NETOS_GNU_TOOLS
#include <sys/types.h>          /* ssize_t */
#endif

#ifdef __ghs__
#include "ddi.h"
#endif

#include <Npttypes.h>
#include <tx_api.h>
#include <starttcp.h>
#include <bsptimer.h>
#include <boardParams.h>
#include <termios.h>
#include <netosIo.h>
#include <narmbrd.h>
#include <hdlcapi.h>
#include <sysAccess.h>
#include <narmapi.h>
#include <dialog.h>
#include <netoserr.h>
#include <nawait.h>
#include <appconf_api.h>

#include "narmnvrm.h"
#include <Flash.h>
#include "dbprintf.h"
#include "naflash.h"
#include "sflash.h"
#include "bsp_sys.h"
#include "bsp_net.h"
#include "bsp_serial.h"	/* not really needed */
#include "bsp_drivers.h"
#include "bsp_fs.h"
#include "bsp_cli.h"
#include "bsp_api.h"
#include "NAsntp.h"
#include "rtc.h"
#include "errhndlr.h"
#include <cliapi.h>
#include <ncc_init.h>
/* treck stack includes */
#include "trsocket.h"
#include "trossupport.h"
#include "nastatus.h"
#include "bsp_local.h"

#ifdef BSP_OLD_SERIAL_PROTOCOL
#include "serParam.h"		/* Need this header for old serial protocol. */
#endif
#include "natimer.h"
#include "timerPrivate.h"
#define OUT_OF_MEMORY       10

#ifdef NETOS_GNU_TOOLS
#include <sys/fcntl.h>
#include <unistd.h>
#include "gdb.h"
#include "debuggercmds.h"

#if (PROCESSOR == ns9215)
#include "a2d_epoch.h"
#endif

#if BSP_GDB_SERVER_ENABLE
#include "armgdb.h"
#endif

#if BSP_WANT_PPP
#include <pppapi.h>
#endif

#if BSP_ENABLE_USB_HOST
#include "usb_start.h"
#endif

#if (BSP_WANT_WIRELESS == TRUE) && (BSP_WANT_WPA == TRUE)
#include "wln_api.h"
#include "wpa_api.h"
#endif

#if (BSP_WPS_START == TRUE)
#include "wps_api.h"
extern void naDialogHandleWps(void);
#endif

#ifdef DOTNETMF
#ifndef BSP_DHCP_STARTUP_TIMEOUT
#define BSP_DHCP_STARTUP_TIMEOUT  0
#endif
#include "iam_netos.hh"
#endif


#if BSP_QUAD_DECODER_ENABLE
#include "quad_api.h"
#endif

#if (PROCESSOR == ns9215)
#include "scratchpad.h"
#endif

#if (PROCESSOR == ns9210 || PROCESSOR == ns9215)
#include "bsp_lowpower.h"
#if (BSP_WANT_HW_AES)
#include "aes_dma_api.h"
#endif
#endif

#ifdef NETOS_GNU_TOOLS
#ifdef NETOS_GNU_CLIB_REENT
extern int naTxGlobalStdioFd;
extern struct _reent *_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
struct _reent * naDefaultImpurePtr = NULL;
#endif
#endif

/* 
 * typedefs needed for mapping internal read/write functions into those
 * used by stdin/stdout/stderr
 */
typedef _ssize_t (*readtype) (void *, char *, int);
typedef _ssize_t (*writetype) (void *, const char *, int);

#define CHECK_INIT(fp) \
  do                                    \
    {                                   \
      if ((fp)->_data == 0)             \
        (fp)->_data = _REENT;           \
      if (!(fp)->_data->__sdidinit)     \
        __sinit ((fp)->_data);          \
    }                                   \
  while (0)
#endif

TX_THREAD rootThread;           /* thread control block for root thread */
TX_TIMER tcp_down_timer;        /* timer to call TCP down function at startup */

static unsigned long timerLoops = 200;

int bsp_kernel_started = 0;     /* set after ThreadX has started */

/*
 * This routine returns TRUE if the only IPv4 addresses we have so far were 
 * derived from Auto-IP.
 */
#if (BSP_WANT_WIRELESS == TRUE) || (BSP_WANT_ETHERNET == TRUE)
static unsigned isOnlyAutoIp(void)
{
    unsigned result = TRUE;
#if (BSP_WANT_WIRELESS == TRUE) || (BSP_WANT_ETHERNET == TRUE) || (BSP_ETH_WIFI_BRIDGE)
    NaIamIfAddrInfo_t addrInfo;
#else   
    result = FALSE;     /* if no network interface, then test is invalid*/
#endif

#if BSP_ETH_WIFI_BRIDGE
    if (customizeIamGetIfAddrInfo(BP_EWB_INTERFACE, &addrInfo) == NA_IAM_STATUS_SUCCESS)
    {
        result = ((addrInfo.method == NA_IAM_METHOD_AUTOIP) || (addrInfo.method == NA_IAM_METHOD_NONE));
    }
#else
#if (BSP_WANT_WIRELESS == TRUE)
    if (customizeIamGetIfAddrInfo(BP_WLN_INTERFACE, &addrInfo) == NA_IAM_STATUS_SUCCESS)
    {
        result = ((addrInfo.method == NA_IAM_METHOD_AUTOIP) || (addrInfo.method == NA_IAM_METHOD_NONE));
    }
#endif
#if (BSP_WANT_ETHERNET == TRUE)
    if ((result) && (customizeIamGetIfAddrInfo(BP_ETH_INTERFACE, &addrInfo) == NA_IAM_STATUS_SUCCESS))
    {
        result = ((addrInfo.method == NA_IAM_METHOD_AUTOIP) || (addrInfo.method == NA_IAM_METHOD_NONE));
    }
#endif
#endif

    return result;
}
#endif

#ifdef DOTNETMF
static void dotNetWaitForDhcp (void)
{
#if BSP_DHCP_STARTUP_TIMEOUT != 0
    if (customizeGetEthernetPresent() != 0)
    {
        NaIamIfAddrInfo_t addrInfo;
        unsigned long now = tx_time_get();
 
        while (   customizeIamGetIfAddrInfo(BP_ETH_INTERFACE, &addrInfo) == NA_IAM_STATUS_SUCCESS
               && addrInfo.method == NA_IAM_METHOD_AUTOIP 
               && (tx_time_get() - now) < NS_MILLISECONDS_TO_TICKS(BSP_DHCP_STARTUP_TIMEOUT * 1000)
              )
        {
            tx_thread_sleep (1);
        }
    }
#endif
}
#endif

/*
 *
 *  Function: void tcp_down_function(ULONG arg)
 *
 *  Description:
 *
 *		This function is called on a 1 tick timer. 
 *		It calls user function applicationTcpDown() while TCP /IP stack 
 *		is not fully configured. 
 *
 *  Parameters:
 *
 *      not used
 *
 *  Return Values:
 *
 *      none
 *
 */

static void tcp_down_function (ULONG arg)
{
    NA_UNUSED_PARAM(arg);
    if (NAGetIPConfigureState() != naIpStateConfigured)
        applicationTcpDown ();
}

//
// Delay for usec microseconds
//
void naWaitInMicroSec (unsigned long usec)
{
	volatile long n = usec*timerLoops/10;

	while (n-- > 0)
		;
}

//
// Calibrate the spin loop in waitUS()
//
// We need 10us resolution, but the threadx timer is only accurate to 10ms.
// Use it to calibrate a large number of iterations of the spin loop in waitUS().
//
void naInitWaitLoop (unsigned long ten_usec_cnt)
{
	unsigned long t;

	// Initial guess
	timerLoops = ten_usec_cnt;

	// Time 10000 iterations using hardware timer
	t = (tx_time_get() * (1000 / NABspTicksPerSecond));
	naWaitInMicroSec (100000);
	t = (tx_time_get() * (1000 / NABspTicksPerSecond)) - t;

	// Calculate loops for 10us delay
	if (t != 0)
		timerLoops = 10000/t;
}


/*
 *
 *  Function: netosConfigStdio(none)
 *
 *  Description:
 *
 *      This routine sets up stdin, stdout, and stderr to be redirected
 *      out the APP_STDIO_PORT if APP_STDIO_PORT is defined.  Typically,
 *      APP_STDIO_PORT is set to either "/com/0" or "/com/1".
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */

void netosConfigStdio (void)
{
    char *valueStr;
    struct termios tios;

    int fd, rc, baudrate;
    static devBoardParamsType nvParams;
#ifdef BSP_OLD_SERIAL_PROTOCOL
    int arg;
#endif

    valueStr = NAGetAppStdioPort ();
    if (valueStr == NULL)
    {
        #ifdef __ghs__
            stdin->io_channel = DDI_HOST_EMULATION_BIT;
            stdout->io_channel = DDI_HOST_EMULATION_BIT | 1;
            stderr->io_channel = DDI_HOST_EMULATION_BIT | 2;
        #endif
        return;
    }

    /*
     *  customizeReadDevBoardParams() reads the contents of the section of NVRAM that contains
     *  the development board's startup parameters if APP_USE_NVRAM flag is set to a nonzero value.
     *  If APP_USE_NVRAM is 0, customizeReadDevBoardParams() reads the default parameters as defined
     *  in appconfig.h. customizeReadDevBoardParams() and default data struct are in 
     *  src\bsp\customize\boardParams.c.
     */
    customizeReadDevBoardParams (&nvParams);

    /* if we have bad baudrate by any chance, then set it to default 9600
       to get things going */
    baudrate = nvParams.baudrate;
    if ((baudrate != 1200) && (baudrate != 2400) && (baudrate != 4800) && (baudrate != 9600)
        && (baudrate != 19200) && (baudrate != 38400) && (baudrate != 57600) && (baudrate != 115200))
    {
        nvParams.baudrate = defaultParams.baudrate;
        baudrate = defaultParams.baudrate;

    }
    /* open device */
    fd = open (valueStr, O_RDWR);
    if (fd < 0)
    {
        netosFatalError ("APP_STDIO_PORT improperly defined", 1, 1);
        return;
    }

/*
 * This ioctl tells the serial driver to set the baud rate
 * from the setting in defaultParams.baudrate
 */

#ifdef BSP_OLD_SERIAL_PROTOCOL
    rc=ioctl(fd, SIO_BAUD_SET , (char *)&baudrate);
	if (rc <0)
	{
		netosFatalError("APP_STDIO_PORT can't set option", 1, 1);
		return;
    }
#else
    tcgetattr(fd, &tios);
    cfsetospeed(&tios, baudrate);
    rc = tcsetattr(fd, TCSANOW, &tios);
    if (rc < 0)
    {
        netosFatalError ("APP_STDIO_PORT can't set option", 1, 1);
        return;
    }
#endif

/*
 * This ioctl tells the serial driver to add a carriage return
 * whenever it transmits a line feed character.
 */
#ifdef BSP_OLD_SERIAL_PROTOCOL
	arg = TERM_SEND_CR_ON;
	rc=ioctl(fd, SIO_TERM_SEND_CR, (char *)&arg);
	if (rc <0)
	{
		netosFatalError("APP_STDIO_PORT can't set option", 1, 1);
		return;
	}
#else
    tcgetattr(fd, &tios);
    tios.c_oflag |= ONLCR;
    rc = tcsetattr(fd, TCSANOW, &tios);
    if (rc < 0)
    {
        netosFatalError ("APP_STDIO_PORT can't set option", 1, 1);
        return;
    }
#endif

/*
 * Now redirect I/O out the selected port.
 */

#if defined(__CC_ARM)
    stdin->handle = fd;
    stdout->handle = fd;
    stderr->handle = fd;
#elif defined NETOS_GNU_TOOLS
    CHECK_INIT (stdin);
    CHECK_INIT (stdout);
    CHECK_INIT (stderr);

    /* need to overwrite the following so that
       std I/O will call into DDI */
    stdout->_cookie = (_PTR) fd;
    stdin->_cookie = (_PTR) fd;
    stderr->_cookie = (_PTR) fd;

    stdout->_file = fd;
    stdin->_file = fd;
    stderr->_file = fd;

    stdin->_read = (readtype) read;
    stdout->_write = (writetype) write;
    stderr->_write = (writetype) write;
#ifdef NETOS_GNU_CLIB_REENT
    naTxGlobalStdioFd = fd;
#endif
#else
    stdin->io_channel = fd;
    stdout->io_channel = fd;
    stderr->io_channel = fd;
#endif

/*
 * Configure the stdin, stdout and stderr for the default GNU C library reentrancy structure.
 * C++ IO streams use the default reentrancy structure instead of the per thread reentrancy structure.
 */
#ifdef NETOS_GNU_TOOLS
#ifdef NETOS_GNU_CLIB_REENT

    /* The following section of code is a workaround to allow C++ cout streams to work */
    /* properly with the updated GNU C library that supports the per thread reentrancy */
    /* feature.  The C++ cout stream does not support the per thread reeentrancy       */
    /* feature so it uses the default reentrancy structure created when the system is  */
    /* initialized.  Performing a printf() with the default reentrancy structure       */
    /* updates the structure such that is usable by the C++ cout stream.               */

    TX_INTERRUPT_SAVE_AREA
    TX_DISABLE
    struct _reent * temp_impure_ptr = NULL;
    temp_impure_ptr = _impure_ptr;
    _impure_ptr = naDefaultImpurePtr;
    printf("\n");
    _impure_ptr = temp_impure_ptr;
    TX_RESTORE

    CHECK_INIT(naDefaultImpurePtr->_stdin);
    CHECK_INIT(naDefaultImpurePtr->_stdout);
    CHECK_INIT(naDefaultImpurePtr->_stderr);

    naDefaultImpurePtr->_stdin->_cookie = (_PTR) fd;
    naDefaultImpurePtr->_stdout->_cookie = (_PTR) fd;
    naDefaultImpurePtr->_stderr->_cookie = (_PTR) fd;

    naDefaultImpurePtr->_stdin->_file = fd;
    naDefaultImpurePtr->_stdout->_file = fd;
    naDefaultImpurePtr->_stderr->_file = fd;

    naDefaultImpurePtr->_stdin->_read = (readtype) read;
    naDefaultImpurePtr->_stdout->_write = (writetype) write;
    naDefaultImpurePtr->_stderr->_write = (writetype) write;
    
#endif
#endif
}


static void setupTime (devBoardParamsType nvParams)
{
#if BSP_INCLUDE_SNTP

#define IPBUFFERLEN 16

	char PrimaryServer[IPBUFFERLEN];
	char SecondaryServer[IPBUFFERLEN];
	int CallStatus = 0;

	if (NAGetAppUseNetworkTimeProtocol ())
	{
	    /* Setup SNTP for retreiving time.
         * It will resynchronizes every 18000 sec (5 hours).
	    */

        memset(&PrimaryServer[0], '\0', IPBUFFERLEN);
        memset(&SecondaryServer[0], '\0', IPBUFFERLEN);

		strcpy(PrimaryServer, NAGetSntpPrimaryServer ());
		/* check params first, if none, check appconf.h */
		strcpy(SecondaryServer, NAGetSntpSecondaryServer());
		PrimaryServer[IPBUFFERLEN - 1] = '\0';
		SecondaryServer[IPBUFFERLEN - 1] = '\0';


        /* start up sntp making both a primary and a secondary server address available */
		CallStatus = NASntpTimeInstall (&PrimaryServer[0], &SecondaryServer[0], 
		                                     nvParams.timezone.sync_time, BSP_SNTP_CALLBACK);

        if(CallStatus != 0)
            {
            netosFatalError ("Unable to install SNTP service", 1, 1);
            }

        /* 
         * assume EST time zone
         * daylight saving time starts at 2:00am on Sunday, the first week of April
         * daylight saving time ends at 2:00am on Sunday, the last week of October
         *
         */
        if (NAinstallTimeZone (nvParams.timezone.std_zone_offset, nvParams.timezone.dst_zone_offset, 
                               nvParams.timezone.dst_start_rule, nvParams.timezone.dst_end_rule) != 0)
        {
            netosFatalError ("Unable to install Time zone", 1, 1);
        }
    }
#elif BSP_INCLUDE_RTC_DRIVER 

    #define BUILD_YEAR          (2007)
	NaRtcTime_t defaultTime, currentTime;
    unsigned int    rtc_id = 0;
    NaStatus        rc;

    /*set up Real Time Clock for retreiving time */
    defaultTime.hundredths_second = 0;
    defaultTime.seconds = 0;
    defaultTime.minutes = 2;
    defaultTime.hours = 11;
    defaultTime.dayOfWeek = NA_RTC_WEDNESDAY;
    defaultTime.date = 27;
    defaultTime.month = NA_RTC_OCTOBER;
    defaultTime.year = 2004;

    rc = naRtcOpen(rtc_id);

    if (rc == NASTATUS_SUCCESS)
    {
#ifdef DOTNETMF
        unsigned needToInitRtc = FALSE;
#else
        unsigned needToInitRtc = TRUE;
#endif
        
        if (naRtcGetTime(rtc_id, &currentTime) == NASTATUS_SUCCESS)
        {
            if (currentTime.year >= BUILD_YEAR)
            {
                needToInitRtc = FALSE;
            }
        }
        if (needToInitRtc)
        {
            if (naRtcSetTime(rtc_id, &defaultTime) != NASTATUS_SUCCESS)
            {
                netosFatalError ("Unable to set Real Time Clock", 1, 1);
            }
        }
        /*set up Real Time Clock for retreiving time */
        if (naRtcLinkToCLibrary(rtc_id) != NASTATUS_SUCCESS)
        {
            netosFatalError ("Unable to install Real Time Clock", 1, 1);
        }
        /* 
         * assume EST time zone
         * daylight saving time starts at 2:00am on Sunday, the first week of April
         * daylight saving time ends at 2:00am on Sunday, the last week of October
         *
         */
        if (naTimeZoneInstall(-nvParams.timezone.std_zone_offset, -nvParams.timezone.dst_zone_offset, 
                               nvParams.timezone.dst_start_rule, nvParams.timezone.dst_end_rule) == FALSE)
        {
            netosFatalError ("Unable to install Time zone", 1, 1);
        }
    }
    else if (rc != NASTATUS_RTC_NOT_AVAILABLE)
    {
        netosFatalError ("Unable to initialize Real Time Clock", 1, 1);
    }
#else

    (void)nvParams; /* Unused parameter */

#endif

}

/*
 *
 *  Function: void netosStartup (ULONG not_used)
 *
 *  Description:
 *
 *      This is the entry point for the root thread.  This thread loads the device
 *      drivers and starts the IP stack.  Then it starts the user's application.
 *
 *  Parameters:
 *
 *      not_used        an unused parameter
 *
 *  Return Values:
 *
 *      none
 *
 */

void netosStartup (ULONG not_used)
{
    static devBoardParamsType nvParams;
    int ret;

#if (BSP_CLI_ENABLE && (BSP_CLI_SERIAL_ENABLE || BSP_CLI_TELNET_ENABLE || BSP_CLI_SSH_ENABLE))
    static NaCliCfg_t cli_cfg;
#endif

    char *valueStr;
    BOOLEAN sleep_wakeup = NAPDIsSleepWakeup();

    NA_UNUSED_PARAM(not_used);

#ifdef FOR_DIGI_MANUFACTURING
    {
        extern void mfgStartup(void);

        mfgStartup();

    }
#endif

    /*
     * Setup the timer routines to use ThreadX semaphores.
     */
     NATimerInstallSemaphore();

    /*
     * Setup the board parameters code to use the C Library malloc routines.
     */
     NABoardParamsSetMalloc(malloc, free);
#if (BSP_NVRAM_DRIVER == BSP_NVRAM_LAST_2_FLASH_SECTORS)
    /*
     * Initialize the NVRAM backup sector if we are using it.
     */
    NANVInitBackupSector();
#endif
    /*
     * Install the semaphore used by debugging output routines.
     */
#ifdef NETOS_DEBUG
    NAInstallDebugSemaphore ();
#endif

    /*
     * Initialize the semaphores in the flash driver.
     */
    if (NAFlashCreateSemaphores () == NAFLASH_SEMAPHORE_CREATE_FAILED)
    {
#ifdef DOTNETMF
		bsp_printf("netosStartup(): Unable to create Flash Driver semaphores\n");
#endif
        netosFatalError ("Unable to create Flash Driver semaphores", 1, 1);
    }


#if (BSP_WANT_WIRELESS == TRUE) && (BSP_ENABLE_DIALOG == FALSE)
    /* 
     * Intialize wireless network interface, we start the wireless driver early
     * if we have no dialog enabled so we can start scanning to 
     * reduce the time to associate with an AP, this is done 
     * to reduce the overall bootup time.
     */

    /* Load 802.11 FPGA image. */
    if(InitWirelessHw() != 0)
    {
        printf("InitWirelessHw Failed\r\n");
        return;
    }

    /* Setup the supported countries for this platform */
    wln_setup_supported_countries();

    if (wireless_init() < 0)
    {
        bsp_printf("netosStartup(): Unable to start wireless driver\n");
        netosFatalError ("Unable to start wireless driver", 1, 1);
    }
#endif


	/* load MMU for SPI driver */
	simplespi_mmu_init();

#if (PROCESSOR == ns9215)
    naA2dEpoch();
#endif

	/*
     * Initialize the semaphores in the serial flash driver.
     */
#if (BSP_NVRAM_DRIVER ==   BSP_NVRAM_LAST_SFLASH_SECTOR)
#if (BSP_NVRAM_DRIVER !=   BSP_NVRAM_NONE)

	NANVInit ((char *) BSP_EEPROM_BASE, BSP_EEPROM_SIZE); 
	if (NASerialFlashCreateSemaphores () == NASERIAL_FLASH_SEMAPHORE_CREATE_FAILED)
    {
#ifdef DOTNETMF
		bsp_printf("netosStartup(): Unable to create Flash Driver semaphores\n");
#endif
        netosFatalError ("Unable to create Serial Flash Driver semaphores", 1, 1);
    }
#endif
#endif


    /*
     * Set thread sleep function for LED driver.  Up to now it's been using
     * a spin loop.
     */
    NAWaitSetSleepFn (tx_thread_sleep);

    /* if the APP_USE_NVRAM flag is set to 0, default from the file is used. */

    /*if (!APP_USE_NVRAM) */
    /* changed 07/27/00. defaultParams will always be loaded with the contents of
     * appconf.h
     */
    customizeUseDefaultParams (&defaultParams);
#if (BSP_WANT_WIRELESS == TRUE) && (BSP_WANT_WPA == TRUE)
    /*
     * Update the Wireless PSK if we are building for wireless and wpa, and if the user has
     * specified a passphrase in appconf.h.  This is stored as a default value to be used
     * if we have trouble reading NVRAM, or if NVRAM has been disabled.  We do this here
     * rather than in boardParams.c file so that we won't pull in the wpa libary into the
     * bootloader.
     *
     * Note:  This is processor intensive and will cause a delay.  Set APP_WLN_PASSPHRASE in
     *        appconf.h to NULL to avoid this delay.  
     */
    if (NAGetAppWlnPsk() == NULL)   /* if user did not specify PSK in appconf.h */
    {
        if ((NAGetAppWlnPassphrase() != NULL) && (NAGetAppWlnSsid() != NULL))
        {
            uint8 wpa_psk[WLN_PSK_SIZE];
            
            wpa_passphrase_to_psk (NAGetAppWlnPassphrase(), NAGetAppWlnSsid(), strlen(NAGetAppWlnSsid()), wpa_psk);
            customizeSetDefaultWlnPsk(wpa_psk);
        }
    }
#endif

    /*
     * The device driver file handles use sockets so they can be integrated
     * with the Treck select() function.  Therefore, we must call trStartTreck()
     * before we open any devices.  To make sure this is so, we do it here
     * before we initialize the device drivers.
     */
    (void) tfInitTreckOptions(TM_OPTION_DHCP_MAX_ENTRIES, 1);
#if BSP_ENABLE_IP_FORWARDING
    (void) tfInitTreckOptions(TM_OPTION_IP_FORWARDING, 1);
#endif
    ret = tfStartTreck();
    if (ret != TM_ENOERROR)
    {
#ifdef DOTNETMF
		bsp_printf("netosStartup(): tfStartTreck failed!\n");
#else
        printf("netosStartTCP: tfStartTreck failed!");
#endif
    }
/*
 * Load device drivers.
 */

#if BSP_ENABLE_HDLC
        naHdlcLoad (NAHDLC_LARGE_FRAME_SIZE, NAHDLC_SMALL_FRAME_SIZE, NAHDLC_NUM_LARGE_FRAMES,
                    NAHDLC_NUM_SMALL_FRAMES, NAHDLC_NUM_EMPTY_FRAMES);
#endif

    DDISecondLevelInitialize ();        /* load each device driver */
    bsp_kernel_started = 1;     /* basic kernel is up now */

/*
 * Create TCP down timer.
 */
#ifdef DOTNETMF
    tx_timer_create (&tcp_down_timer, "tcp down timer", tcp_down_function, 0, 100, 100, TX_AUTO_ACTIVATE);
#else
    tx_timer_create (&tcp_down_timer, "tcp down timer", tcp_down_function, 0, 1, 1, TX_AUTO_ACTIVATE);
#endif

#if (BSP_WANT_WIRELESS == TRUE) && (BSP_ENABLE_DIALOG == TRUE)
/* 
 * Load 802.11 FPGA image.
 */
    if(InitWirelessHw() != 0)
    {
        printf("InitWirelessHw Failed\r\n");
        return;
    }

    /* setup the supported countries for this platform */
    wln_setup_supported_countries();
#endif



    /* Zigbee (to access Zigbee radio via serial interface) */
    zbs_epoch();     

/*
 * Init PPP module
 */
#if BSP_WANT_PPP
    if (PPPInit() != 0)
    {
        printf("PPPInit() failed\n");
        return;
    }
#endif

#if (PROCESSOR == ns9210 || PROCESSOR == ns9215)
#if (BSP_WANT_HW_AES)
    if (naAesInit())
    {
        printf("naAesInit() failed\n");
        return;
    }
#endif
#endif
    
	/* move this earlier in the start sequence to enable flash access for
	 * the nvram access functions on the cc9p9360. jhl */
#if (BSP_INCLUDE_FILESYSTEM_FOR_CLIBRARY || BSP_INCLUDE_FAT_FILESYSTEM_FOR_CLIBRARY)
    if (filesystem_init ())     /*initialize file system for C lib functions and ftp, email, http modules */
    {
        netosFatalError ("Unable to initialize file system", 1, 1);
    }
#endif

#ifdef NETOS_GNU_TOOLS
    naExecuteDebuggerCommands();
#endif

    if ((valueStr = NAGetAppRootPassword ()))
    {
        customizeReadDevBoardParams (&nvParams);
        if (nvParams.rootPassword[0] == 0)
        {
            /*  Use the default root password defined in APP_ROOT_PASSWORD  */
            NAsetSysAccess (NASYSACC_ADD, "root", valueStr, NASYSACC_LEVEL_ROOT, NULL);
        }
        else
        {
            /*  Use the root password from NVRAM    */
            NAsetSysAccess (NASYSACC_ADD, "root", nvParams.rootPassword, NASYSACC_LEVEL_ROOT, NULL);
        }
    }

#if BSP_GDB_SERVER_ENABLE && defined NETOS_GNU_TOOLS
    naGdbStart(NA_GDB_COMPORT); 
#endif

/*
 * Prompt user with dialog to set configuration parameters.
 */
#if BSP_ENABLE_DIALOG
    if (!sleep_wakeup)
        customizeDialog ();


#if (BSP_WPS_START == TRUE)
    if (naWpsInit(NULL) != NASTATUS_SUCCESS)
    {
        netosFatalError ("Unable to intialize WPS", 1, 1);
    }

    naDialogHandleWps();
#endif

#endif

    customizeReadDevBoardParams (&nvParams);    /* read new settings from NVRAM */

    netosConfigStdio ();        /* redirect stdio if so configured */
    
#if BSP_ENABLE_USB_HOST
    /*
     * Start USB host AND USB class drivers
     */
    if ((ret = NaStartUsbHost()) != 0)
    {
        printf("NaStartUsbHost failed, error = [%d]\r\n", ret);
        return;
    }
#endif

    /*
     * If this board has an ethernet port
     */
    if (customizeGetEthernetPresent() != 0)
    {
       /* start the TCP stack */
        netosStartTCP();

        if (NAWaitForIpConfig == TRUE)
        {
#if (BSP_WANT_WIRELESS == TRUE) || (BSP_WANT_ETHERNET == TRUE)
            WORD32 autoIpDelayTicks = NABspAutoIpDelay * NABspTicksPerSecond;
            
            while (NAGetIPConfigureState() != naIpStateConfigured)        /* wait until stack has IP parameters */
            {
                tx_thread_sleep (1);    /* let other tasks run */
            }
            while ((isOnlyAutoIp()) && (autoIpDelayTicks != 0))
            {
                autoIpDelayTicks--;
                tx_thread_sleep(1);
            }
#endif
        }
    }

#ifdef DOTNETMF
    dotNetWaitForDhcp ();
#endif

    if (!sleep_wakeup)
        printf("Network IP configured.\n");
   
     /* Delete TCP down timer. */
    tx_timer_delete (&tcp_down_timer);

    if ((valueStr = NAGetAppAdministratorsAccount ()))
    {
        if (nvParams.adminPassword[0] != 0)
        {
            /*  Use the administrators password from NVRAM    */
            NAsetSysAccess (NASYSACC_ADD, valueStr, nvParams.adminPassword, NASYSACC_LEVEL_GATEWAY, 0);
        }
    }

    /*setup time for time function */
    setupTime (nvParams);


    /* Start the CLI if enabled in bsp_cli.h */
#if (BSP_CLI_ENABLE && (BSP_CLI_SERIAL_ENABLE || BSP_CLI_TELNET_ENABLE || BSP_CLI_SSH_ENABLE))

    memset(&cli_cfg, 0, sizeof cli_cfg);

#if BSP_CLI_SERIAL_ENABLE
    
    cli_cfg.serial_port = BSP_CLI_COM_PORT;

#endif

#if BSP_CLI_TELNET_ENABLE
    cli_cfg.telnet_port = BSP_CLI_TELNET_PORT;
#endif

#if BSP_CLI_SSH_ENABLE 
    cli_cfg.sshKeyFilename = BSP_CLI_SSH_KEY_FILENAME;
    cli_cfg.sshKeyPassword = BSP_CLI_SSH_KEY_PASSWORD;
#endif

    if (naCliOpen(&cli_cfg) < 0)
    {
        printf("Unable to start CLI\r\n");
        return;
    }
    if (!sleep_wakeup)
        printf("CLI Started.\n");
#endif

#if BSP_QUAD_DECODER_ENABLE
	if (naQuadratureInit() != 0)
	{
		printf("Unable to initialize quadrature decoder\r\n");
	}
#endif

#if (PROCESSOR == ns9215)
    if (naScratchpadInit() != NA_SUCCESS)
    {
        printf("Unable to initialize scratch pad\r\n");
    }
#endif

/*
 * Start low power mode if selected.
 */
#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
#if BSP_LOW_POWER_MODE_ENABLE

    if (!NAPdIsLowPowerKernel)
    {
        panic("You must link your application against libtx_lp.a if BSP_LOW_POWER_MODE_ENABLE is set.");
    }
    naPdCatnapSetCpuToAhbClockRatio(BSP_LOW_POWER_MODE_LOW_SPEED_CPU_CLOCK_RATIO, NAPD_CATNAP_LOW_SPEED);
    naPdCatnapStart(BSP_LOW_POWER_MODE_TRIGGERS, BSP_LOW_POWER_MODE_LOW_SPEED_DIVISOR, 1);
#endif
#endif

/*
 * Start the user's application.
 */
#ifdef DOTNETMF
	tfSeedRng(naRandSeed());
#endif
    applicationStart ();
}

/*
 *
 *  Function: void tx_application_define (void *first_unused_memory)
 *
 *  Description:
 *
 *      ThreadX is hard coded to call this function after it has initialized.
 *      This function is called just before the ThreadX scheduler starts.  It
 *      creates the root thread that is responsible for starting NET+OS and
 *      the IP stack.
 *
 *  Parameters:
 *
 *      first_unused_memory     pointer to first piece of unused memory
 *
 *  Return Values:
 *
 *      none
 *
 */

void tx_application_define (void *first_unused_memory)
{
    int ccode;
    int stack_size;
    int priority;
    BYTE *stack;

    NA_UNUSED_PARAM (first_unused_memory);

/*
 * Start the system and aux clocks.
 */
    netosStartClocks ();

/*
 * Save the default _impure_ptr from the GNU C library, so we can update it later 
 */
#ifdef NETOS_GNU_TOOLS
#ifdef NETOS_GNU_CLIB_REENT
    naDefaultImpurePtr = _impure_ptr;
#endif
#endif

/*
 * Get the stack size and priority from configurations for root thread
 */
    priority = NAGetAppRootPriority ();
    stack_size = NAGetAppRootStackSize ();
    stack = malloc (stack_size);
    if (stack == NULL)
    {
        customizeErrorHandler(ERROR_OUT_OF_MEMORY, ERROR_NO_SUBCODE);
    }

/*
 * Now create the root thread which starts NET+OS and the TCP/IP stack.
 */
    ccode = tx_thread_create (&rootThread,      /* control block for root thread */
                              "Root Thread",    /* thread name */
                              netosStartup,     /* entry function */
                              0,        /* parameter */
                              stack,    /* start of stack */
                              stack_size,       /* size of stack */
                              priority, /* priority */
                              priority, /* preemption threshold */
                              1,        /* time slice threshold */
                              TX_AUTO_START);   /* start immediately */

    if (ccode != TX_SUCCESS)    /* if couldn't create thread */
    {
        netosFatalError ("Unable to create root thread", 1, 1);
    }
}

#ifdef ENABLE_FLASH_COMPRESSION
const char ram_buffer_0[] = { 0 };
#else

void decompress (void)
{
}
#endif


