/*
   Copyright (c) 2015, Digi International Inc.

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**************************************************************
  FAT_UCOS.C

  Demonstrate using FAT with uC/OS-II.

  Requires that you run this on a board with a compatible
  storage medium (serial flash, NAND flash or SD card).

  Versions of the Dynamic C FAT prior to 2.10 did not support
  FAT unless all FAT API calls are done in one task.

  FAT_USE_UCOS_MUTEX must be #defined before #use'ing FAT.LIB

  fat_InitUCOSMutex(priority)  MUST be called after calling
  OSInit() and before calling FAT APIs or begining multitasking.
  'priority' MUST be higher than all tasks using FAT APIs.

  Only high level fat APIs with names that begin with 'fat_'
  should be called from uC/OS-II tasks.

**************************************************************/
#memmap xmem

#define OS_MUTEX_EN		       1	 	// Enable mutexes
#define OS_TIME_DLY_HMSM_EN	 1    // Enable hour, min, sec, ms delays
#define OS_TASK_SUSPEND_EN     1    // Enable task ssuspension

// Must use mutexes to multitask with FAT,
//  and must use blocking mode
#define FAT_USE_UCOS_MUTEX
#define FAT_BLOCK

// Create 1024 task stacks for FAT tasks just to be safe
#define STACK_CNT_1K 2

// Bring in libraries
#use "ucos2.lib"
#use "fat.lib"
#ifndef FAT_VERSION
  #error "This program requires FAT version 2.10 or greater"
#endif

int taskcount;

#define  FILESIZE 4096
char fbuff1[FILESIZE];
char fbuff2[FILESIZE];

void File1Task(void* pdata);
void File2Task(void* pdata);

void main()
{
   int rc;

   OSInit();
   taskcount = 0;

   // MUST Initialize FAT mutex at higher priority than other tasks
   fat_InitUCOSMutex(4);

   rc = fat_AutoMount(FDDF_MOUNT_PART_0    | FDDF_MOUNT_DEV_0     |
                      FDDF_COND_DEV_FORMAT | FDDF_COND_PART_FORMAT );
   if(rc)
   {
      printf("ERROR: fat_AutoMount() failed: %ls\n", error_message(rc));
      exit(rc);
   }

   OSTaskCreate(File1Task, NULL, 1024, 5);
   OSTaskCreate(File2Task, NULL, 1024, 6);
   OSStart();  // Start multi-tasking
}

void File1Task(void* pdata)
{
   auto FATfile my_file;
   auto char ch;
   auto int i, rc;

   while(1){
      OSTimeDlyHMSM(0,0,0,100);  // Allow lower priority taskes to run

      // PARTITION_A = partition 0  on device 0
      fat_Open(PARTITION_A, "file1.txt",FAT_FILE, FAT_CREATE, &my_file, NULL);

      // Fill file with whatever is in the low byte of MS_TIMER
      ch = (char)MS_TIMER;
      memset(fbuff1, ch, FILESIZE);
      fat_Write(&my_file, fbuff1, FILESIZE);

      // Make sure it reads back correctly
      memset(fbuff1, 0, FILESIZE);             // clear buffer
      fat_Seek(&my_file, 0L, SEEK_SET);
      fat_Read(&my_file, fbuff1, FILESIZE);

      for(i=0;i<FILESIZE;i++){
         if( fbuff1[i] != ch){
             printf("ERROR:fat_Read() bad value\n");
             break;
         }
      }
      if (i==FILESIZE){
         if(fat_Delete(PARTITION_A, FAT_FILE, "file1.txt" ))
         {
             printf("Task1 successful\n");
         }
         else{
             printf("ERROR:fat_Delete() bad value\n");
         }
      }
      fat_Close(&my_file);

      // quit after 4 passes so we don't wear out flash if left running
      if(taskcount++ > 4){
         fat_UnmountDevice(PARTITION_A->dev);
         printf("Test done: Hit any key to end program");
         OSTaskSuspend(6);
         while(!kbhit());
         exit(0);
      }
   }
}

void File2Task(void* pdata)
{
   auto FATfile my_file;
   auto char ch;
   auto int i, rc;

   while(1){
     fat_Open(PARTITION_A, "file2.txt",
                 FAT_FILE, FAT_CREATE, &my_file, NULL);

      // Fill file with whatever is in the low byte of MS_TIMER
      ch = (char)MS_TIMER;
      memset(fbuff2, ch, FILESIZE);
      fat_Write(&my_file, fbuff2, FILESIZE);

      // Make sure it reads back correctly
      memset(fbuff2, 0, FILESIZE);         // clear buffer
      fat_Seek(&my_file, 0L, SEEK_SET);
      fat_Read(&my_file, fbuff2, FILESIZE);

      for(i=0;i<FILESIZE;i++){
         if( fbuff2[i] != ch){
             printf("ERROR:fat_Read() bad value\n");
             break;
         }
      }
      if (i==FILESIZE){
         if(fat_Delete( PARTITION_A, FAT_FILE, "file2.txt" )){
             printf("Task2 successful\n");
         }
         else{
             printf("ERROR:fat_Delete() bad value\n");
         }
      }
      fat_Close(&my_file);
   }
}

