/*
 *  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
 *
 * Description.
 * =======================================================================
 * applicationStart() is the entry point for user applications.  This
 * This function will be called after the kernel has started and the
 * TCP/IP stack has loaded.  applicationTcpDown() is called periodically
 * after the kernel has started while the system is waiting for the
 * TCP/IP stack to start.
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 *
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <tx_api.h>
#include "appconf.h"

#define MAX_NAME_LEN 128

void startAThread(void);

void threadToCrash(unsigned long theParam);

typedef struct threadDefStruct
{
	TX_THREAD theThreadCB;
	char theThreadName[MAX_NAME_LEN];
	void * theTheadStack;
	unsigned long theThreadStackSize;
	void (*theThreadFunc)(unsigned long);
	unsigned long theThreadInput;
} threadDefStructType;

#if 0
threadDefStructType theThreadtable[] =
{
		{{0}, "First Thread", NULL, 4096, threadToCrash, 0}
};

#define NUMBER_OF_THREADS (sizeof(theThreadtable)/ sizeof(theThreadtable[0]))
#endif

#define MAX_SIZE_OF_BUFFER 100

/*
 * Define this to 1 for the buffer to be located in GLBAL space
 * Define this to 0 for it to be in stack space
 */
#define WANT_BUFFER_IN_GLOBAL_SPACE 0

/*
 * Define this to 1 if buffer is to be malloced
 * Define this to 0 if buffer is to be declared and not malloced
 */
#define WANT_BUFFER_MALLOCED 0

#if (WANT_BUFFER_MALLOCED == 1)
#if (WANT_BUFFER_IN_GLOBAL_SPACE == 1)
char * theJunkArray;
#endif //buffer in global space
#endif // buffer malloced

#if (WANT_BUFFER_MALLOCED == 0)
#if (WANT_BUFFER_IN_GLOBAL_SPACE == 1)
char theJunkArray[MAX_SIZE_OF_BUFFER];
#endif //buffer in global space
#endif // buffer malloced

/*
 * DEfine this as 1 for a buffer overflow. DEfine as 0 for an underflow
 */
#define WANT_BUFFER_OVERFLOW 0

int theLoopIdx = 0;
int loopIndex = 0;
int theInteger = 0;



/*
 *
 *  Function: void applicationTcpDown (void)
 *
 *  Description:
 *
 *      This routine will be called by the NET+OS root thread once every
 *      clock tick while it is waiting for the TCP/IP stack to come up.
 *      This function can increment a counter everytime it's called to
 *      keep track of how long we've been waiting for the stack to start.
 *      If we've been waiting too long, then this function can do something
 *      to handle the error.
 *
 *      This function will not be called once the stack has started.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */

void applicationTcpDown (void)

{
    static int ticksPassed = 0;

    ticksPassed++;
/*
 * Code to handle error condition if the stack doesn't come up goes here.
 */
}




/*
 *
 *  Function: void applicationStart (void)
 *
 *  Description:
 *
 *      This routine is responsible for starting the user application.  It should
 *      create any threads or other resources the application needs.
 *
 *      ThreadX, the NET+OS device drivers, and the TCP/IP stack will be running
 *      when this function is called.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */

void applicationStart (void)

{

	/*
	 * Code to start the user application goes here.
	 */
	printf ("Cause a crash\n");

	printf(" applicationStart starts at address [%x]\n",(unsigned int)applicationStart );

	printf("calling Start a thread\n");
	startAThread();

    tx_thread_suspend(tx_thread_identify());
}

void threadToCrash(unsigned long theParam)
{

/*
 * These defines are defined at the beginning of the program
 */
#if (WANT_BUFFER_MALLOCED == 1)
#if (WANT_BUFFER_IN_GLOBAL_SPACE == 0)
char * theJunkArray;
#endif //buffer in global space
#endif // buffer malloced

#if (WANT_BUFFER_MALLOCED == 0)
#if (WANT_BUFFER_IN_GLOBAL_SPACE == 0)
char theJunkArray[MAX_SIZE_OF_BUFFER];
#endif //buffer in global space
#endif // buffer malloced



	printf("In thread threadToCrash\n");

/*
 * This define is defined at the beginning of the program
 */
#if (WANT_BUFFER_MALLOCED == 1)
	theJunkArray = malloc(100);
	if(theJunkArray == NULL)
	{
		printf("Unable to malloc the array\n");
		return;
	}

	printf("Buffer malloced\n");
#endif

	memset(theJunkArray, '\0', 100);
    printf("theJunkArray is at [%x]\n", (unsigned int)theJunkArray);

    theInteger = 1000;
    while(1)
	{
		theJunkArray[loopIndex] = 'A';
#if (WANT_BUFFER_OVERFLOW == 1)
		loopIndex++;
#else
		loopIndex--;
#endif
		theLoopIdx++;
		tx_thread_sleep(2);
	}


}

void startAThread()
{
	unsigned int theUIStatus = TX_SUCCESS;
	int theLoopIdx = 0;
	static threadDefStructType theThreadtable[] =
	{
			{{0}, "First Thread", NULL, 4096, threadToCrash, 0}
	};

	#define NUMBER_OF_THREADS (sizeof(theThreadtable)/ sizeof(theThreadtable[0]))

    for(theLoopIdx = 0; theLoopIdx < NUMBER_OF_THREADS; theLoopIdx++)
    {
    	theThreadtable[theLoopIdx].theTheadStack = malloc(theThreadtable[theLoopIdx].theThreadStackSize);
    	if(theThreadtable[theLoopIdx].theTheadStack == NULL)
    	{
    		printf("Unable to malloc stack space\n");
    		return;
    	}
    	memset(theThreadtable[theLoopIdx].theTheadStack, '\0', theThreadtable[theLoopIdx].theThreadStackSize);
    	memset(&theThreadtable[theLoopIdx].theThreadCB, '\0', sizeof(TX_THREAD));
    	theUIStatus = tx_thread_create(&theThreadtable[theLoopIdx].theThreadCB,
    			theThreadtable[theLoopIdx].theThreadName,
    			theThreadtable[theLoopIdx].theThreadFunc,
    			theThreadtable[theLoopIdx].theThreadInput,
    			theThreadtable[theLoopIdx].theTheadStack,
    			theThreadtable[theLoopIdx].theThreadStackSize,
    			15, 15, 10, TX_AUTO_START);
    	if(theUIStatus != TX_SUCCESS)
    	{
    		printf("Unable to start thread\n");
    		return;
    	}
    }


}



