/*
 *  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 <errno.h>
#include <string.h>

#include "tx_api.h"
#include "fs.h"
#include "netosIo.h"
#include "bsp_api.h"
#include "sysAccess.h"
#include "bsp.h"

/* set or unset this flag to choose between testing flash or ram volume */
#define	FLASH_TEST

#ifdef	FLASH_TEST
#define RAM_VOLUME      "FLASH0"

#define RAM_DIR1        "FLASH0/DIR1"
#define RAM_DIR1_DIR1   "FLASH0/DIR1/DIR1"
#define RAM_NODIR       "FLASH0/INVALIDDIR"
#define RAM_FILENAME    "FLASH0/test.txt"
#define RAM_DIR1_FILENAME   "FLASH0/DIR1/test.txt"
#define RAM_DIR1_FILENAME1  "FLASH0/DIR1/test1.txt"
#else
#define RAM_VOLUME      "RAM0"

#define RAM_DIR1        "RAM0/DIR1"
#define RAM_DIR1_DIR1   "RAM0/DIR1/DIR1"
#define RAM_NODIR       "RAM0/INVALIDDIR"
#define RAM_FILENAME    "RAM0/test.txt"
#define RAM_DIR1_FILENAME   "RAM0/DIR1/test.txt"
#define RAM_DIR1_FILENAME1  "RAM0/DIR1/test1.txt"
#endif

#define FILE_SIZE          (1 * 1024) /* 320 * 1024  */
#define	NAF_RDBUF_SZ 512
/* static char write_buffer[NAF_RDBUF_SZ]; */
static char read_buffer[NAF_RDBUF_SZ + 1];	/* allow for null terminate */


#define MULT_OF_FILE_DATA       2000
#define APP_STACK_SIZE          8 * 1024
#define FOPEN_RETRIES           4

TX_THREAD app_thread1, app_thread2, app_thread3;
void app_thread1_entry();
void app_thread2_entry();
void app_thread3_entry();
extern int getErrno (void);
volatile int app_thread1_completed = 0;
volatile int app_thread2_completed = 0;
volatile int app_thread3_completed = 0;

char *file_data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *file_data1 = "01234567890123456789012345678901234567890123456789"; 
char *file_data2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *file_data3 = "abcdefghijklmnopqrstuvwxyz";

void mkdir_test(void)
{
    int rc;
    char *dirname;
    
    
#ifndef NETOS_DEBUG    
    rc = remove(NULL);
    if (rc == 0)	/* returns 0 on success */
    {
        printf("mkdir_test: ERROR - should have error on creating NULL directory\n");
    }
#endif    
    dirname = RAM_DIR1;
    /* directory under volume */
    rc = mkdir(dirname, 0);
    if (rc != 0)
    {
        printf("mkdir: fails %s errno = %d\n", dirname, getErrno());        
    }
    else
    {   /* sub-directory */
		printf("successfully created directory %s\n\r", dirname);
        dirname = RAM_DIR1_DIR1;
        rc = mkdir (dirname, 0);
        if (rc != 0)
        {
            printf("mkdir: fails %s errno = %d\n", dirname, getErrno());        
        }
        else
        {   
			printf("successfully created sub-directory %s\n\r", dirname);
            /* duplicate directory */
            rc = mkdir (dirname, 0);
            if (rc == 0)
                printf("mkdir: ERROR - mkdir should have failed on creating duplicate %s directory\n", dirname);        
			else
					printf("creating duplicate directory was refused\n\r");
        }
    }
    
    return;
}
        
void remove_test(void)
{
    int rc;
    char *dirname = NULL;
    
#ifndef NETOS_DEBUG    
    rc = remove(NULL);	/* returns 0 on success */
    if (rc == 0)
    {
        printf("remove_test: ERROR - expected error on removing NULL directory\n");
    }
	else
		printf("correct response removing NULL directory\n\r");
#endif    

    rc = remove(RAM_NODIR);
    if (rc == 0)
    {
        printf("remove_test: ERROR - expected error on removing non-exist \"%s\" directory\n", RAM_NODIR);
    }
	else
		printf("correct response removing non-existent directory\n\r");
    
    dirname = RAM_DIR1;
    rc = remove(dirname);
    if (rc == 0)
    {
        printf("remove: ERROR - expected error on removing on empty \"%s\" directory\n", dirname);
    }
	else
		printf("correct response: rejected removing non-empty directory\n\r");
    
    /* directory under volume */
    dirname = RAM_DIR1_DIR1;
    rc = remove(dirname);
    if (rc != 0)
    {
        printf("remove: fails \"%s\" errno = %d\n", dirname, getErrno());
    }
    else
    {   /* sub-directory */
        dirname = RAM_DIR1;
        rc = remove(dirname);
        if (rc != 0)
        {
            printf("remove: fails \"%s\" errno = %d\n", dirname, getErrno());        
        }
        /* duplicate directory */
        rc = remove(dirname);
        if (rc == 0)
        {
            printf("remove: ERROR - should have failed \"%s\" errno = %d\n", dirname, getErrno());
        }
		else
			printf("correct response failing to remove deleted directory\n\r");
    }
    
    return;
}

void open_test(void)
{
    char *filename;
    int  mode, rc;
    // int  permissions = NASYSACC_FS_GROUP1_READ | NASYSACC_FS_GROUP1_WRITE;
	// yaffs fs_config set for GROUP2
    int  permissions = NASYSACC_FS_GROUP2_READ | NASYSACC_FS_GROUP2_WRITE;
    
#ifndef NETOS_DEBUG    
    rc = open(NULL, O_RDONLY);
    if (rc != -1)
    {
        printf("open_test: ERROR - should have failed on open with NULL filename %d\n", getErrno());
    }
    
    filename = RAM_FILENAME;
    
/*    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL|O_RDWR|O_TRUNC|O_WRONLY|0xf000; */
    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL|O_RDWR|O_TRUNC|O_WRONLY|-1;
    printf("\nopen: 1. 0x%X mode\n", mode);
    rc = open(filename, mode, permissions);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc > 0)
    {
        printf("open_test: ERROR - should have failed to open \"%s\" with invalid mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
        close(rc);
    }
	else
		printf("correct result\n\r");

    mode = O_RDONLY;
    printf("\nopen: 2. 0x%X mode\n", mode);
    rc = open (filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc > 0)
    {
        printf("open_test: ERROR - should have failed to open non-exist \"%s\" file with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
        close(rc);
    }
	else
		printf("correct result\n\r");
#endif        

    filename = RAM_FILENAME;
    
    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL|O_RDWR|O_TRUNC|O_WRONLY;
    printf("\nopen: 3. 0x%X mode\n", mode);
    rc = open(filename, mode, permissions);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   
		printf("correct result\n\r");
		close(rc);
    }
    
    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL|O_RDWR|O_TRUNC;
    printf("\nopen: 4. 0x%X mode\n", mode);
    rc = open(filename, mode, permissions);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc > 0)
    {
        printf("open_test: ERROR - should have failed to open \"%s\" (already exists) with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
        close(rc);
    }
	else
		printf("correct result\n\r");
    /* Create directory for creating files in the subdirectory */    
    rc = mkdir(RAM_DIR1, 0);
    if (rc != 0 && getErrno() != EEXIST)
    {
        printf("open_test: mkdir \"%s\" fails errno = %d\n", RAM_DIR1, getErrno());        
        goto _ret;
    }
    
    filename = RAM_DIR1_FILENAME;
    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL|O_RDWR;
    printf("\nopen: 5. 0x%X mode\n", mode);
    rc = open(filename, mode, permissions);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
		printf("correct result\n\r");
        close(rc);
    }

    filename = RAM_DIR1_FILENAME1;
    mode = O_RDONLY|O_APPEND|O_CREAT|O_EXCL;
    printf("\nopen: 6. 0x%X mode\n", mode);
    rc = open(filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
		printf("correct result\n\r");
        close(rc);
    }

    mode = O_RDONLY|O_APPEND|O_CREAT;
    printf("\nopen: 7. 0x%X mode\n", mode);
    rc = open(filename, mode, permissions);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
		printf("correct result\n\r");
        close(rc);
    }
    
    mode = O_RDONLY|O_APPEND;
    printf("\nopen: 8. 0x%X mode\n", mode);
    rc = open(filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
		printf("correct result\n\r");
        close(rc);
    }
    
    mode = O_RDONLY;
    printf("\nopen: 9. 0x%X mode\n", mode);
    rc = open(filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
		printf("correct result\n\r");
        close(rc);
    }
    

    mode = O_WRONLY;
    printf("\nopen: 10. 0x%X mode\n", mode);
    rc = open (filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - should have failed to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
	{
		printf("correct result\n\r");
        close(rc);
	}

    mode = O_CREAT;
    printf("\nopen: 11. 0x%X mode\n", mode);
    rc = open (filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_test: ERROR - fails to open \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {
        close(rc);
		printf("correct result\n\r");
    }

    mode = O_CREAT|O_EXCL;
    printf("open: 12. 0x%X mode\n", mode);
    rc = open (filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc > 0)
    {
        printf("open_test: ERROR - expected error for creating \"%s\" with mode 0x%X (%d errno)\n", 
                    filename, mode, getErrno());
        close(rc);
    }
	else
		printf("correct result\n\r");
    
_ret:    
    return;
}


void open_write_test(void)
{
    char *filename;
    char *dataPtr;
    int rc;
    int mode;
    int file_size, numberOfBytes;
    int total_size, total_size1;
    int sendlen;
    int wrote;
    int j;
    
    filename = RAM_FILENAME;
    
    mode = O_CREAT|O_RDWR;
    printf("\nopen_write_test: 1. O_CREAT|O_RDWR (0x%X) \n", mode);
    rc = open (filename, mode);
	printf("open %s returned %d\n\r", filename, rc);
    if (rc == -1)
    {
        printf("open_write_test: ERROR - open on \"%s\" with mode 0x%X\n", filename, mode);
        goto _ret;
    }
	else
		printf("correct result\n\r");
    
    printf("\nopen_write_test: open \"%s\" file with 0x%X mode file_number %d\n", filename, mode, rc);    
    
    file_size = strlen(file_data);
	wrote = 0;
	printf("writing %d bytes %d at a time\n\r", FILE_SIZE, file_size);
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = write(rc, dataPtr, sendlen);	 
#ifdef	FILEIO_VERBOSE
            printf("open_write_test: writing 0x%X bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }
        
    printf("open_write_test: wrote %d bytes\n\n", wrote);
    total_size = wrote;
        
	if (close(rc) != 0)
    {
        printf("open_write_test: ERROR - close on file_number %x errno = %d\n\n", rc, getErrno());
        goto _ret;
    }    
	else
		printf("successfully closed file\n\r");
        
    mode = O_WRONLY|O_APPEND;
    printf("\nopen_write_test: 2. O_WRONLY|O_APPEND (0x%X) \n", mode);
	rc = open((const char *)filename, mode);
    if (rc == -1)
    {
        printf("open_write_test: ERROR - open on \"%s\" with mode 0x%X\n", filename, mode);
        goto _ret;
    }
	else
		printf("correct result\n\r");
    
    printf("\nopen_write_test: open \"%s\" file with 0x%X mode file_number %d\n", filename, mode, rc);    
    
    file_size = strlen(file_data1);
	printf("writing %d bytes %d at a time\n\r", FILE_SIZE, file_size);
	wrote = 0;
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data1;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = write(rc, dataPtr, sendlen);	 
#ifdef	FILEIO_VERBOSE
            printf("open_write_test: writing 0x%X bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }
        
    printf("open_write_test: appended %d bytes\n\n", wrote);
    total_size1 = wrote;

    numberOfBytes = read(rc, read_buffer, NAF_RDBUF_SZ);
    if (numberOfBytes > 0)
    {
        printf("open_write_test: ERROR - should have failed on O_WRONLY mode file_number = %d number of bytes read = %d\n", 
                            rc, numberOfBytes);
    }
	else
		printf("correct result -- fail to read write-only file\n\r");
    
	if (close(rc) != 0)
    {
        printf("open_write_test: ERROR - close fails file_number = %d\n", rc);
    }

    mode = O_CREAT|O_EXCL;
    printf("\nopen_write_test: 3. O_CREAT|O_EXCL (0x%X) \n", mode);
	rc = open((const char *)filename, mode);
    if (rc != -1)
    {
        printf("open_write_test: ERROR - open should have failed %d on \"%s\" with mode 0x%X (create only)\n", rc, filename, mode);
        goto _ret;
    }
	else
		printf("correct result -- fail to open existing file create only\n\r");
    
    mode = O_RDONLY;
    printf("\nopen_write_test: 4. O_RDONLY (0x%X) \n", mode);
	rc = open((const char *)filename, mode);
    if (rc == -1)
    {
        printf("open_write_test: ERROR - open fails on \"%s\" with mode 0x%X\n", filename, mode);
        goto _ret;
    }
	printf("file opened successfully\n\r");
#ifdef	FILEIO_VERBOSE
    printf("\n\n--------------\n");
#endif
    file_size = 0;
    do
    {
        numberOfBytes = read(rc, read_buffer, NAF_RDBUF_SZ);
        if (numberOfBytes > 0)
        {
            read_buffer[numberOfBytes] = '\0';
            file_size += numberOfBytes;
#ifdef	FILEIO_VERBOSE
            printf("%d - %s", numberOfBytes, read_buffer);
#endif
        }
    } while (numberOfBytes > 0);
        
#ifdef	FILEIO_VERBOSE
    printf("\n--------------\n");
    printf("Total size %d + %d = %d\n\n", total_size, total_size1, file_size);
#endif
    if ((total_size + total_size1) != file_size)
    {
        printf("open_write_test: ERROR - fails the size should be %d\n", (total_size + total_size1)); 
    }
	else
		printf("correct result -- read %d bytes file size %d\n\r",
						total_size + total_size1, file_size);
    
	if (close(rc) != 0)
    {
        printf("open_write_test: ERROR - close on file_number %x errno = %d\n\n", rc, getErrno());
        goto _ret;
    }    
    
    printf("\nopen_write_test: 5. remove %s\n", filename);
        
    rc = remove((const char *)filename);    /*file should be removed */
    if (rc != 0)
        printf ("open_write_test: ERROR - remove fails on \"%s\" file\n", filename);
	else
		printf("correct result -- file %s removed successfully\n\r", filename);
 
_ret: 
    return;       
}        
        
void fopen_test(void)
{
    char *filename;
    FILE  *fp, *fp2, *fp3, *fp4, *fp5;
    char *mode, *mode2, *mode3, *mode4, *mode5;

#ifndef NETOS_DEBUG    
    mode = "r";
    printf("\nfopen_test: 1. NULL file with \"%s\" \n", mode);
    fp = fopen(NULL, (const char *)mode);
    if (fp != NULL)
    {
        printf("fopen_test: ERROR - should have failed on fopen with NULL filename %d\n", getErrno());
    }
	else
		printf("correct result opening NULL in %s mode\n\r", mode);
    
    filename = RAM_FILENAME;
    
    mode = "d";
    printf("\nfopen_test: 2. %s file with \"%s\" \n", filename, mode);
    fp = fopen(filename, mode);
    if (fp != NULL)
    {
        printf("fopen_test: ERROR - should have failed to open \"%s\" with invalid mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
	else
		printf("correct result opening %s in %s mode\n\r", filename, mode);

    mode = "r";
    printf("\nfopen_test: 3. %s file with \"%s\" \n", filename, mode);
    fp = fopen (filename, mode);
    if (fp != NULL)
    {
        printf("fopen_test: ERROR - should have failed to open non-exist \"%s\" file with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
	else
		printf("correct result opening %s in %s mode\n\r", filename, mode);    
#endif

    filename = RAM_FILENAME;

    mode = "w";
    printf("\nfopen_test: 4. %s file with \"%s\" \n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   
        printf("correct result opening %s in %s mode\n\r", filename, mode);
        fclose(fp);
    }
    
    mode = "w+";
    printf("\nfopen_test: 5. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        printf("correct result opening %s in %s mode\n\r", filename, mode);
        fclose(fp);
    }
    
    mode = "r+";
    printf("\nfopen_test: 6. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

        
    mode = "a";
    printf("\nfopen_test: 7. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    
    mode = "a+";
    printf("\nfopen_test: 8. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }
    
    mode = "rb";
    printf("\nfopen_test: 9. %s file with \"%s\" \n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }
    
    mode = "rt";
    printf("\nfopen_test: 10. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    
    mode = "wt";
    printf("\nfopen_test: 11. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {   /* close the file */
        fclose(fp);
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    /************************************************************
     * This section tests multiple opens per file, where a file *
     * can be opened once for write but multiple times for read *
     * Only "r" and "r+" modes are allowed for subsequent opens *
     ************************************************************/

    /************************************************************
     * Test initial file open in read and write mode followed by*
     * more file opens in read and/or write mode                *
     ***********************************************************/

    mode = "w";
    mode2 = "a";
    mode3 = "r";
    mode4 = "r+";
    mode5 = "r";

    printf("\nfopen_test: 12. Open %s file multiple times with \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", filename, mode, mode2, mode3, mode4, mode5);
    printf("\nfopen_test: 12. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    printf("\nfopen_test: 12. %s file with \"%s\"\n", filename, mode2);
    fp2 = fopen(filename, mode2);
    if (fp2 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode2, getErrno());
        printf("this result is correct because the file is already opened in write mode\n");
    }
    else
    {
        printf("incorrect result opening %s in %s mode\n\r", filename, mode2);
        printf("this result is incorrect because the file is already opened in write mode\n");

    }

    printf("\nfopen_test: 12. %s file with \"%s\"\n", filename, mode3);
    fp3 = fopen(filename, mode3);
    if (fp3 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode3, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode3);
    }

    printf("\nfopen_test: 12. %s file with \"%s\"\n", filename, mode4);
    fp4 = fopen(filename, mode4);
    if (fp4 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode4, getErrno());
        printf("this result is correct because the file is already opened in write mode\n");
    }
    else
    {
        printf("incorrect result opening %s in %s mode\n\r", filename, mode4);
        printf("this result is incorrect because the file is already opened in write mode\n");

    }

    printf("\nfopen_test: 12. %s file with \"%s\"\n", filename, mode5);
    fp5 = fopen(filename, mode5);
    if (fp5 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode5, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode5);
    }

    /* close the files */
    if (fp)
    {
        if (fclose(fp))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode, getErrno());
        }
    }
    if (fp2)
    {
        if (fclose(fp2))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode2, getErrno());
        }
    }
    if (fp3)
    {
        if (fclose(fp3))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode3, getErrno());
        }
    }
    if (fp4)
    {
        if (fclose(fp4))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode4, getErrno());
        }
    }
    if (fp5)
    {
        if (fclose(fp5))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode5, getErrno());
        }
    }

    /************************************************************
     * Test initial file open in read only mode followed by more*
     * file opens in read and/or write mode                     *
     ***********************************************************/
    mode = "r";
    mode2 = "a+";
    mode3 = "w+";
    mode4 = "r+";
    mode5 = "r";

    printf("\nfopen_test: 13. Open %s file multiple times with \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", filename, mode, mode2, mode3, mode4, mode5);
    printf("\nfopen_test: 13. %s file with \"%s\"\n", filename, mode);
    fp = fopen(filename, mode);
    if (fp == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    printf("\nfopen_test: 13. %s file with \"%s\"\n", filename, mode2);
    fp2 = fopen(filename, mode2);
    if (fp2 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode2, getErrno());
        printf("this result is correct because the \"a\", \"a+\", \"w\" and \"w+\" modes are not supported for subsequent file opens\n");
    }
    else
    {
        printf("incorrect result opening %s in %s mode\n\r", filename, mode2);
        printf("this result is incorrect because the file is already opened in write mode\n");
    }

    printf("\nfopen_test: 13. %s file with \"%s\"\n", filename, mode3);
    fp3 = fopen(filename, mode3);
    if (fp3 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode3, getErrno());
        printf("this result is correct because the \"a\", \"a+\", \"w\" and \"w+\" modes are not supported for subsequent file opens\n");
    }
    else
    {
        printf("incorrect result opening %s in %s mode\n\r", filename, mode2);
        printf("this result is correct because the \"a\", \"a+\", \"w\" and \"w+\" modes are not supported for subsequent file opens\n");
    }

    printf("\nfopen_test: 13. %s file with \"%s\"\n", filename, mode4);
    fp4 = fopen(filename, mode4);
    if (fp4 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode4, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode);
    }

    printf("\nfopen_test: 13. %s file with \"%s\"\n", filename, mode5);
    fp5 = fopen(filename, mode5);
    if (fp5 == NULL)
    {
        printf("fopen_test: ERROR - fails to open \"%s\" with mode %s (%d errno)\n", 
                    filename, mode5, getErrno());
    }
    else
    {
        printf("correct result opening %s in %s mode\n\r", filename, mode5);
    }

    /* close the files */
    if (fp)
    {
        if (fclose(fp))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode, getErrno());
        }
    }
    if (fp2)
    {
        if (fclose(fp2))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode2, getErrno());
        }
    }
    if (fp3)
    {
        if (fclose(fp3))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode3, getErrno());
        }
    }
    if (fp4)
    {
        if (fclose(fp4))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode4, getErrno());
        }
    }
    if (fp5)
    {
        if (fclose(fp5))
        {
            printf("fopen_test: ERROR - fails to close \"%s\" when opened in mode %s (%d errno)\n", 
                    filename, mode5, getErrno());
        }
    }
    
    return;
}


void fopen_write_test(void)
{
#define	OFFSET_BEYOND
   	/* bytes to be written with 0 for fseek at EOF */
#define _ZEROWRITE_OFFSET   10

    char *filename;
    FILE *fp;
    char *dataPtr;
    char *mode;
    int file_size, numberOfBytes;
    int total_size;
#ifdef	FILEIO_VERBOSE
    int zerowrite_size;
#endif
    int sendlen, offset;
    int wrote;
    int ret;
    int j;
    
    filename = RAM_FILENAME;
 
    mode = "w";
    printf("\n********************************\n");
    printf("\nfopen_write_test: 1. %s file with \"%s\" (overwrite)\n",
				   	filename, mode);
    fp = fopen (filename, (const char *)mode);
    if (fp == NULL)
    {
        printf("fopen_write_test: ERROR - open on \"%s\" with mode %s errno = %d\n", 
                    filename, mode, getErrno());
        goto _ret;
    }
	else
		printf("correct result\n\r");
    
#ifdef	FILEIO_VERBOSE
    printf("             writing \"%s\" data\n", file_data);
#endif
    file_size = strlen(file_data);
	printf("writing %d bytes %d at a time %s mode %s\n\r",
				  FILE_SIZE, file_size, filename, mode);
	wrote = 0;
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = fwrite(dataPtr, sizeof(char), sendlen, fp);	 
#ifdef	FILEIO_VERBOSE
            printf("fopen_write_test: writing %d bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }
        
    printf("    --------- Total file size = %d -----------\n\n", wrote);
    total_size = wrote;
        
	if (fclose(fp) != 0)
    {
        printf("fopen_write_test: ERROR - close errno = %d\n\n", getErrno());
        goto _ret;
    }    
	else
		printf("closed file successfully\n\r");

    /* The previous data should be overwritten */
    mode = "w";
    printf("\n********************************\n");
    printf("\nfopen_write_test: 2. %s file with \"%s\" (overwrite)\n",
				   	filename, mode);
    fp = fopen (filename, (const char *)mode);
    if (fp == NULL)
    {
        printf("fopen_write_test: ERROR - open on \"%s\" with mode %s errno = %d\n", 
                    filename, mode, getErrno());
        goto _ret;
    }
	else
		printf("correct result\n\r");
    
#ifdef	FILEIO_VERBOSE
    printf("             writing \"%s\" data\n", file_data1);
#endif
    file_size = strlen(file_data1);
	printf("writing %d bytes %d at a time %s mode %s\n\r",
				   	FILE_SIZE, file_size, filename, mode);
	wrote = 0;
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data1;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = fwrite(dataPtr, sizeof(char), sendlen, fp);	 
#ifdef	FILEIO_VERBOSE
            printf("fopen_write_test: writing %d bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }

    printf("    --------- Total file size = %d -----------\n\n", wrote);
    total_size = wrote;
        
	if (fclose(fp) != 0)
    {
        printf("fopen_write_test: ERROR - close errno = %d\n\n", getErrno());
        goto _ret;
    }    
	else
		printf("closed file successfully\n\r");

    /* data should be appended */        
    mode = "a";

    printf("\n********************************\n");
    printf("\nfopen_write_test: 3. %s file with \"%s\" (append)\n",
				   	filename, mode);
	fp = fopen(filename, (const char *)mode);
    if (fp == NULL)
    {
        printf("fopen_write_test: ERROR - open on \"%s\" with mode %s errno = %d\n", 
                    filename, mode, getErrno());
        goto _ret;
    }

    /* We should read nothing */
    numberOfBytes = fread(read_buffer, sizeof(char), NAF_RDBUF_SZ, fp);
    if (numberOfBytes > 0)
    {
        printf("open_write_test: ERROR - expected reading 0 since it's eof (fread returns %d)\n", 
                        numberOfBytes);
    }
	else
		printf("correct result - read returned 0 from EOF\n\r");
    if (ferror(fp))
    {
        printf("open_write_test: ERROR - expected read error on append mode (%d)\n", numberOfBytes);
    }
	else
		printf("ferror(fp) is %d\n\r", ferror(fp));
    
#ifdef	FILEIO_VERBOSE
    printf("             writing \"%s\" data\n", file_data);
#endif
    file_size = strlen(file_data);
	printf("writing %d bytes %d at a time to %s mode %s\n\r",
				   	FILE_SIZE, file_size, filename, mode);
	wrote = 0;
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = fwrite(dataPtr, sizeof(char), sendlen, fp);	 
#ifdef	FILEIO_VERBOSE
            printf("fopen_write_test: writing %d bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }
        
    printf("    --------- Appended %d bytes to file -----------\n\n", wrote);
    total_size += wrote;  /* added for the total size of the file */

	if (fclose(fp) != 0)
    {
        printf("fopen_write_test: ERROR - close fails errno = %d\n", getErrno());
    }
	else
		printf("closed file successfully\n\r");
    /* append data */
    mode = "r+";
    printf("\n********************************\n");
    printf("\nfopen_write_test: 4. %s file with \"%s\"\n", filename, mode);
    fp = fopen (filename, (const char *)mode);
    if (fp == NULL)
    {
        printf("fopen_write_test: ERROR - open on \"%s\" with mode %s errno = %d\n", 
                    filename, mode, getErrno());
        goto _ret;
	}
#ifdef	OFFSET_BEYOND
    /* set offset beyond EOF */    
    printf("             set offset %d after EOF\n", _ZEROWRITE_OFFSET);
    offset = total_size + _ZEROWRITE_OFFSET;
#ifdef	FILEIO_VERBOSE
    zerowrite_size = total_size;
#endif
    
    printf("\nfopen_write_test: total file size = %d set offset 0x%X (%d)\n", 
                total_size, offset, offset);
                
    if (fseek (fp, offset, SEEK_CUR) != 0)
    {
        printf("fopen_write_test: ERROR - fseek fails on \"%s\" offset %d errno = %d\n", 
                        filename, offset, getErrno());
    }
    else 
    {
        total_size = offset;  /* offset */
    }
    /* should write after the offset */
#endif 	/* OFFSET_BEYOND */
#ifdef	FILEIO_VERBOSE
    printf("             writing \"%s\" data\n", file_data1);
#endif
    file_size = strlen(file_data1);
	wrote = 0;
    for (j = 0; j < FILE_SIZE; j += file_size)
    {
        dataPtr = (char *)file_data1;
        sendlen = file_size < FILE_SIZE - wrote ? file_size : FILE_SIZE - wrote;
    	do {
            numberOfBytes = fwrite(dataPtr, sizeof(char), sendlen, fp);	 
#ifdef	FILEIO_VERBOSE
            printf("fopen_write_test: writing %d bytes...\n", numberOfBytes);
#endif
            dataPtr += numberOfBytes;
            sendlen -= numberOfBytes;
			wrote += numberOfBytes;
        } while (sendlen > 0);
    }
        
    printf("    --------- Appended %d bytes to file -----------\n\n", wrote);
    total_size += wrote;
        
    printf("\nfopen_write_test: total file size = %d <====\n",  total_size);
                
	if (fclose(fp) != 0)
    {
        printf("fopen_write_test: ERROR - close errno = %d\n\n", getErrno());
        goto _ret;
    }    
	else
		printf("closed file successfully\n\r");

    mode = "r";
    printf("\n********************************\n");
    printf("\nfopen_write_test: 5. %s file with \"%s\"\n", filename, mode);
	fp = fopen((const char *)filename, mode);
    if (fp == NULL)
    {
        printf("fopen_write_test: ERROR - open fails on \"%s\" with mode %s errno = %d\n", 
                            filename, mode, getErrno());
        goto _ret;
    }
#ifdef	FILEIO_VERBOSE
    printf("\n\n--------------\n");
#endif
    file_size = 0;
    while (! feof(fp) && ! ferror(fp))
    {
        numberOfBytes = fread(read_buffer, sizeof(char), NAF_RDBUF_SZ, fp);
        read_buffer[numberOfBytes] = '\0';
#ifdef	FILEIO_VERBOSE
        if ( (file_size > zerowrite_size && (file_size + numberOfBytes) < (zerowrite_size + _ZEROWRITE_OFFSET)) ||
             (file_size < zerowrite_size && (file_size + numberOfBytes) > zerowrite_size) )
        {
            char *ptr = read_buffer;
            int  size = numberOfBytes;
            int  len;
            
            printf("\n%d - ", numberOfBytes);
            do {
                while (*ptr == '\0' && size > 0)
                {
                    printf(" ");
                    ptr += 1;
                    size -= 1;
                }
                len = printf("%s", ptr);
                size -= len;
                ptr += len;
            } while (size > 0);
            
            
        }
        else
        {
            printf("\n%d - %s", numberOfBytes, read_buffer);
        }
#endif
        file_size += numberOfBytes;
    }    
#ifdef	FILEIO_VERBOSE
    printf("\n--------------\n");
#endif

    if (file_size != total_size)
    {
        printf("fopen_write_test: ERROR - %d bytes were written to the file (including %d zeros offset) = the total file size should be %d\n",
                        total_size, _ZEROWRITE_OFFSET, file_size);
    }
	else
    	printf("Expected %d bytes. Read %d bytes.\n\n", total_size, file_size);
    
    offset = -file_size;    
    if (fseek (fp, offset, SEEK_CUR) == -1)
    {
        printf("fopen_write_test: ERROR - fseek \"%s\" file to %d offset errno = %d\n", 
                            filename, offset, getErrno());
    }
    printf("\n********************************\n");
    printf("\nfopen_write_test: 6. seek to the beginning and read\n");
    
    file_size = 0;
    while (! feof(fp) && ! ferror(fp))
    {
        numberOfBytes = fread(read_buffer, sizeof(char), NAF_RDBUF_SZ, fp);
        read_buffer[numberOfBytes] = '\0';
        file_size += numberOfBytes;
#ifdef	FILEIO_VERBOSE 
		/* beware that %s is chopped by the null chars inserted by seek
		 * beyond the EOF above */
        printf("\n%d - %s", numberOfBytes, read_buffer);
#endif
    }    
#ifdef	FILEIO_VERBOSE 
    printf("\n--------------\n");
#endif
    printf("\n\rread %d bytes to EOF\n\r", file_size);
    
    if (ferror(fp))
    {
        printf("fopen_write_test: error encounters errno = %d\n", getErrno());
    }

    offset = -(file_size+_ZEROWRITE_OFFSET);    
    ret = fseek (fp, offset, SEEK_CUR);
    if (ret == 0)
    {
        printf("fopen_write_test: ERROR - expect error on fseek \"%s\" file to %d offset errno = %d\n", 
                            filename, offset, getErrno());
    }
	else
		printf("Seek before SOF (%d bytes) returned %d. Correct response.\n\r",
					   	offset, ret);
    
    printf("\n********************************\n");
    printf("\nfopen_write_test: 7. set offset to EOF and read\n");
    
    ret = fseek (fp, 0, SEEK_END);
    if (ret == -1)
    {
        printf("fopen_write_test: ERROR - error on fseek \"%s\" file to EOF errno = %d\n", 
                            filename, getErrno());
    }
	else
		printf("seek to END returned %d\n\r", ret);
    
    file_size = 0;
    while (! feof(fp) && ! ferror(fp))
    {
        numberOfBytes = fread(read_buffer, sizeof(char), NAF_RDBUF_SZ, fp);
        read_buffer[numberOfBytes] = '\0';
        file_size += numberOfBytes;
#ifdef	FILEIO_VERBOSE
        printf("\n%d - %s", numberOfBytes, read_buffer);
#endif
    }    
#ifdef	FILEIO_VERBOSE
    printf("\n--------------\n");
#endif
    printf("read returned %d\n\n", file_size);
	if (file_size == 0)
		printf("Correct response\n\r");
    
    
	if (fclose(fp) != 0)
    {
        printf("fopen_write_test: ERROR - close errno = %d\n\n", getErrno());
        goto _ret;
    }    
	else
		printf("closed file successfully\n\r");
    
    if (remove (filename) != 0)
        printf ("fopen_write_test: ERROR - remove fails on \"%s\" file\n", filename);
 
    
 _ret:
    return;       
}        
        
void nafileio_cleanup(void)
{
	unlink(RAM_FILENAME);
	unlink(RAM_DIR1_FILENAME);
	unlink(RAM_DIR1_FILENAME1);
	remove(RAM_DIR1_DIR1);
	remove(RAM_DIR1);
}

void fopen_multithread_test(void)
{
    void * stack_ptr = NULL;
    unsigned int status;

    stack_ptr = malloc(APP_STACK_SIZE);
    if (stack_ptr == NULL)
    {
        printf("fopen_multithread_test: malloc() failed\n");
        goto exit;
    }
    status = tx_thread_create (&app_thread1,               /* control block for thread*/
                               "App Thread 1",             /* thread name*/
                               app_thread1_entry,          /* entry function*/
                               0,                          /* parameter*/
                               stack_ptr,                  /* start of stack*/
                               APP_STACK_SIZE,             /* size of stack*/
                               NABspDefaultPriority,       /* priority*/
                               NABspDefaultPriority,       /* preemption threshold */
                               1,                          /* time slice threshold*/
                               TX_AUTO_START);             /* start immediately*/

    if (status != TX_SUCCESS)
    {
        free (stack_ptr);
        printf("fopen_multithread_test: tx_thread_create() failed, error %d\n", status);
        goto exit;
    }

    stack_ptr = malloc(APP_STACK_SIZE);
    if (stack_ptr == NULL)
    {
        printf("fopen_multithread_test: malloc() failed\n");
        goto exit;
    }
    status = tx_thread_create (&app_thread2,               /* control block for thread*/
                               "App Thread 2",             /* thread name*/
                               app_thread2_entry,          /* entry function*/
                               0,                          /* parameter*/
                               stack_ptr,                  /* start of stack*/
                               APP_STACK_SIZE,             /* size of stack*/
                               NABspDefaultPriority,       /* priority*/
                               NABspDefaultPriority,       /* preemption threshold */
                               1,                          /* time slice threshold*/
                               TX_AUTO_START);             /* start immediately*/


    if (status != TX_SUCCESS)
    {
        free (stack_ptr);
        printf("fopen_multithread_test: tx_thread_create() failed, error %d\n", status);
        goto exit;
    }

    stack_ptr = malloc(APP_STACK_SIZE);
    if (stack_ptr == NULL)
    {
        printf("fopen_multithread_test: malloc() failed\n");
        goto exit;
    }
    status = tx_thread_create (&app_thread3,               /* control block for thread*/
                               "App Thread 3",             /* thread name*/
                               app_thread3_entry,          /* entry function*/
                               0,                          /* parameter*/
                               stack_ptr,                  /* start of stack*/
                               APP_STACK_SIZE,             /* size of stack*/
                               NABspDefaultPriority,       /* priority*/
                               NABspDefaultPriority,       /* preemption threshold */
                               1,                          /* time slice threshold*/
                               TX_AUTO_START);             /* start immediately*/


    if (status != TX_SUCCESS)
    {
        free (stack_ptr);
        printf("fopen_multithread_test: tx_thread_create() failed, error %d\n", status);
        goto exit;
    }
exit:
    return;
}

void app_thread1_entry()
{
    int rc, j, error_no;
    unsigned int bytes_to_read, bytes_to_write;
    unsigned int bytes_written, bytes_read;
    unsigned int file_offset, file_size;
    char * read_buffer = NULL, * rbuffer = NULL;
    char * file_name = RAM_FILENAME;
    FILE * file_ptr = NULL;

    file_size = MULT_OF_FILE_DATA * strlen(file_data);
    read_buffer = malloc(file_size + 1);
    if (read_buffer == NULL)
    {
        printf("app_thread1_entry: malloc() returned NULL, exiting thread.\n");
        goto exit;
    }
    rbuffer = read_buffer;
    
    file_ptr = fopen(file_name, "w+");
    if (file_ptr == NULL)
    {
        printf("app_thread1_entry: fopen() returned NULL, exiting thread.\n");
        goto exit;
    }

    printf("app_thread1_entry: writing %d bytes to %s\n", file_size, file_name);
    
    file_offset = 0;
    bytes_to_write = strlen(file_data);

    for (j = 0; j < MULT_OF_FILE_DATA; j++)
    {
        rc = fwrite(file_data, bytes_to_write, 1, file_ptr);
        if (!rc)
        {
            error_no = getErrno();
            printf("app_thread1_entry: fwrite() returned 0, errno %d, exiting thread.\n", error_no);
            goto exit;
        }
        else
        {
            if ((rc * bytes_to_write) != bytes_to_write)
            {
                printf("app_thread1_entry: fwrite() write byte count mismatch, exiting thread.\n");
                goto exit;
            }
            bytes_written += bytes_to_write;
        }
        file_offset += bytes_to_write;
    }
    fflush(file_ptr); /* flush all buffered write data to permanent storage */
    printf("app_thread1_entry: finished writing %d bytes to %s\n", file_size, file_name);

    memset(rbuffer, 0x0, file_size + 1);
    file_offset = 0;

    bytes_read = 0;
    bytes_to_read = strlen(file_data2);

    /* move file position indicator to start of file before reading */
    rc = fseek(file_ptr, file_offset, SEEK_SET);
    if (rc)
    {
        printf("app_thread1_entry: fseek() returned error %d, exiting thread.\n", rc);
        goto exit;
    }

    for (j = 0; j < (MULT_OF_FILE_DATA * 2); j++)
    {
        rc = fread(rbuffer, bytes_to_read, 1, file_ptr);
        if (!rc)
        {
            printf("app_thread1_entry: fread() returned 0, exiting thread.\n");
            goto exit;
        }
        else
        {
            if ((rc * bytes_to_read) != bytes_to_read)
            {
               printf("app_thread1_entry: fread() read byte count mismatch, exiting thread.\n");
               goto exit;
            }
            bytes_read += bytes_to_read;
        }
        /* compare the read buffer data with write buffer data for consistency */
        if (j % 2)
        {
            if (memcmp(rbuffer, file_data3, bytes_to_read))
            {
                printf("app_thread1_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
        else
        {
            if (memcmp(rbuffer, file_data2, bytes_to_read))
            {
                printf("app_thread1_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
        file_offset += bytes_to_read;
        rbuffer += bytes_to_read;
    }

    rbuffer = read_buffer;
    bytes_to_read = strlen(file_data);
    for (j = 0; j < MULT_OF_FILE_DATA; j++)
    {
        if (memcmp(rbuffer, file_data, bytes_to_read))
        {
            printf("app_thread1_entry: write buffer and read buffer mismatch, exiting thread.\n");
            goto exit;
        }
        rbuffer += bytes_to_read;
    }

    printf("app_thread1_entry: write data and read data match, so closing file.\n");

    rc = fclose(file_ptr);
    if (rc)
    {
        printf("app_thread1_entry: fclose() returned error %d, exiting thread.\n", rc);
        goto exit;
    }
exit:
    tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(1000));
    if (read_buffer != NULL)
        free(read_buffer);
    app_thread1_completed = 1;
    return;
}

void app_thread2_entry()
{
    int rc, rc2, j, error_no;
    unsigned int bytes_to_read, bytes_read, data_size;
    unsigned int file_offset, file_size;
    char * read_buffer = NULL, * rbuffer = NULL, * rbuffer2 = NULL;
    char * file_name = RAM_FILENAME;
    FILE * file_ptr = NULL;

    file_size = MULT_OF_FILE_DATA * strlen(file_data);
    read_buffer = malloc(file_size + 1);
    if (read_buffer == NULL)
    {
        printf("app_thread2_entry: malloc() returned NULL, exiting thread.\n");
        goto exit;
    }
    rbuffer = read_buffer;

    printf("app_thread2_entry: reading %d bytes from %s\n", file_size, file_name);

    for (j = 0; j < FOPEN_RETRIES; j++)
    {
        file_ptr = fopen(file_name, "r");
        if (file_ptr == NULL)
        {
            error_no = getErrno();
            printf("app_thread2_entry: fopen() returned NULL, errno %d\n", error_no);
            if ((error_no == ENFILE) || (error_no == ENOENT))
            {
                printf("app_thread2_entry: retrying fopen()\n");
                tx_thread_sleep(BSP_TICKS_PER_SECOND);
                continue;
            }
            else
            {
                printf("app_thread2_entry: exiting thread\n");
                goto exit;
            }
        }
        break;
    }
    if (j >= FOPEN_RETRIES)
    {
        printf("app_thread2_entry: attempted fopen() %d times without success, exiting thread.\n", j);
    }
    
    memset(rbuffer, 0x0, file_size + 1);
    file_offset = 0;
    bytes_read = 0;
    data_size = strlen(file_data2);

    for (j = 0; j < (MULT_OF_FILE_DATA * 2); j++)
    {
        bytes_to_read = data_size;
        do
        {
            /* Note: If thread A opened a file in writable mode and thread B  */
            /* opened the same file in "r" mode, then both threads are        */
            /* accessing the same file asynchronously, where thread B is      */
            /* polling the file with fread() for data to read from the file's */
            /* current file pointer.  If the data in the file is an array of  */
            /* fixed sized data structures, you should use fread() with the   */
            /* argument (element size) equal to 1 and the third argument      */
            /* (element count) equal to the the data structure size.  This    */
            /* allows the fread() function to return the number of bytes read */
            /* into the read buffer and allows the user to call fread() to    */
            /* read the remaining bytes of the current data block.            */
            rc = fread(rbuffer, 1, bytes_to_read, file_ptr);
            if (!rc)
            {
                error_no = getErrno();
                if (error_no != EOF)
                {
                    printf("app_thread2_entry: fread() returned 0, errno %d, exiting thread.\n", error_no);
                    goto exit;
                }

                /* use fseek() to clear the EOF status in the file stream */
                rc2 = fseek(file_ptr, 0, SEEK_CUR);
                if (rc2)
                {
                    error_no = getErrno();
                    printf("app_thread2_entry: fseek() returned non-zero, errno %d, exiting thread.\n", error_no);
                }
                tx_thread_sleep(1);
            }
            else
            {
                bytes_read += rc;
                bytes_to_read -= rc;
                file_offset += rc;
                rbuffer2 = rbuffer;
                rbuffer += rc;
            }
        } while (bytes_to_read);

        /* compare the read buffer data with write buffer data for consistency */
        if (j % 2)
        {
            if (memcmp(rbuffer2, file_data3, bytes_to_read))
            {
                printf("app_thread2_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
        else
        {
            if (memcmp(rbuffer2, file_data2, bytes_to_read))
            {
                printf("app_thread2_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
    }

    rbuffer = read_buffer;
    bytes_to_read = strlen(file_data);
    
    for (j = 0; j < MULT_OF_FILE_DATA; j++)
    {
        if (memcmp(rbuffer, file_data, bytes_to_read))
        {
            printf("app_thread2_entry: write buffer and read buffer mismatch, exiting thread.\n");
            goto exit;
        }
        rbuffer += bytes_to_read;
    }

    printf("app_thread2_entry: write data and read data match, so closing file.\n");

    rc = fclose(file_ptr);
    if (rc)
    {
        printf("app_thread2_entry: fclose() returned error %d, exiting thread.\n", rc);
        goto exit;
    }
exit:
    tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(1000));
    if (read_buffer != NULL)
        free(read_buffer);
    app_thread2_completed = 1;
    return;
}

void app_thread3_entry()
{
    int rc, rc2, j, error_no;
    unsigned int bytes_to_read, bytes_read, data_size;
    unsigned int file_offset, file_size;
    char * read_buffer = NULL, * rbuffer = NULL, * rbuffer2 = NULL;
    char * file_name = RAM_FILENAME;
    FILE * file_ptr = NULL;
    
    file_size = MULT_OF_FILE_DATA * strlen(file_data);
    read_buffer = malloc(file_size + 1);
    if (read_buffer == NULL)
    {
        printf("app_thread3_entry: malloc() returned NULL, exiting thread.\n");
        goto exit;
    }
    rbuffer = read_buffer;

    printf("app_thread3_entry: reading %d bytes from %s\n", file_size, file_name);

    for (j = 0; j < FOPEN_RETRIES; j++)
    {
        file_ptr = fopen(file_name, "r");
        if (file_ptr == NULL)
        {
            error_no = getErrno();
            printf("app_thread3_entry: fopen() returned NULL, errno %d\n", error_no);
            if ((error_no == ENFILE) || (error_no == ENOENT))
            {
                printf("app_thread3_entry: retrying fopen()\n");
                tx_thread_sleep(BSP_TICKS_PER_SECOND);
                continue;
            }
            else
            {
                printf("app_thread3_entry: exiting thread\n");
                goto exit;
            }
        }
        break;
    }
    if (j >= FOPEN_RETRIES)
    {
        printf("app_thread3_entry: attempted fopen() %d times without success, exiting thread.\n", j);
    }

    memset(rbuffer, 0x0, file_size + 1);
    file_offset = 0;
    bytes_read = 0;
    data_size = strlen(file_data2);

    for (j = 0; j < (MULT_OF_FILE_DATA * 2); j++)
    {
        bytes_to_read = data_size;
        do
        {
            /* Note: If thread A opened a file in writable mode and thread B  */
            /* opened the same file in "r" mode, then both threads are        */
            /* accessing the same file asynchronously, where thread B is      */
            /* polling the file with fread() for data to read from the file's */
            /* current file pointer.  If the data in the file is an array of  */
            /* fixed sized data structures, you should use fread() with the   */
            /* argument (element size) equal to 1 and the third argument      */
            /* (element count) equal to the the data structure size.  This    */
            /* allows the fread() function to return the number of bytes read */
            /* into the read buffer and allows the user to call fread() to    */
            /* read the remaining bytes of the current data block.            */
            rc = fread(rbuffer, 1, bytes_to_read, file_ptr);
            if (!rc)
            {
                error_no = getErrno();
                if (error_no != EOF)
                {
                    printf("app_thread3_entry: fread() returned 0, errno %d, exiting thread.\n", error_no);
                    goto exit;
                }

                /* use fseek() to clear the EOF status in the file stream */
                rc2 = fseek(file_ptr, 0, SEEK_CUR);
                if (rc2)
                {
                    error_no = getErrno();
                    printf("app_thread3_entry: fseek() returned non-zero, errno %d, exiting thread.\n", error_no);
                }
                tx_thread_sleep(1);
            }
            else
            {
                bytes_read += rc;
                bytes_to_read -= rc;
                file_offset += rc;
                rbuffer2 = rbuffer;
                rbuffer += rc;
            }
        } while (bytes_to_read);

        /* compare the read buffer data with write buffer data for consistency */
        if (j % 2)
        {
            if (memcmp(rbuffer2, file_data3, bytes_to_read))
            {
                printf("app_thread3_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
        else
        {
            if (memcmp(rbuffer2, file_data2, bytes_to_read))
            {
                printf("app_thread3_entry: write buffer and read buffer mismatch, exiting thread.\n");
                goto exit;
            }
        }
    }

    rbuffer = read_buffer;
    bytes_to_read = strlen(file_data);
    
    for (j = 0; j < MULT_OF_FILE_DATA; j++)
    {
        if (memcmp(rbuffer, file_data, bytes_to_read))
        {
            printf("app_thread3_entry: write buffer and read buffer mismatch, exiting thread.\n");
            goto exit;
        }
        rbuffer += bytes_to_read;
    }

    printf("app_thread3_entry: write data and read data match, so closing file.\n");

    rc = fclose(file_ptr);
    if (rc)
    {
        printf("app_thread3_entry: fclose() returned error %d, exiting thread.\n", rc);
        goto exit;
    }
exit:
    tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(1000));
    if (read_buffer != NULL)
        free(read_buffer);
        
    app_thread3_completed = 1;
    return;
}

/*
 *
 *  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)
{
    if (NABspFilesystemForCLib == 0)
    {
        fprintf (stderr, "current BSP does not include file system for Clib\n");
        goto application_done;
    }

    printf("C library to native file system example started\n");
    printf("=====mkdir_test>>>>>>\n");
    mkdir_test();
    
    printf("=====remove_test>>>>>>\n");
    remove_test();

    printf("=====open_test>>>>>>\n");
    open_test();
    
    printf("=====open_write_test>>>>>>\n");
    open_write_test();

    printf("=====fopen_test>>>>>>\n");
    fopen_test();

    printf("=====fopen_write_test>>>>>>\n");
    fopen_write_test();

    printf("=====fopen_multithread_test>>>>>>\n");
    fopen_multithread_test();

    do
    {
        tx_thread_sleep(BSP_TICKS_PER_SECOND);
    }
    while(!app_thread1_completed || !app_thread2_completed || !app_thread2_completed);

    printf("C library to native file system example completed\n");
    printf("cleaning up the test files and directories\n");
    nafileio_cleanup();

application_done:
    tx_thread_suspend (tx_thread_identify ());
}
