/**
* @file   main.c
*
* @brief  This file contains the Petit FAT file system application.
*   
* This module uses the NIOS II core in the Altera Cyclone 2 used on the DE1
* development board. It is assumed the processor core, SRAM, and SPI components
* have been initialized and programmed in the FPGA fabric. Most of this file
* was taken from http://elm-chan.org/fsw/ff/00index_p.html and was modified to
* work with the NIOS II core. 
*
* <pre>
* The following is a list of the IP core base addresses:
*   1 - BTN_BASE:         4 Pushbuttons
*   2 - SWITCH_BASE:      10 slide switches
*   3 - LEDG_BASE:        8 green LEDs
*   4 - LEDR_BASE:        10 red LEDs
*   5 - SSEG_BASE:        4 seven-segment LED displays
*   6 - SD_CARD_BASE:     SD card controller (over SPI)
*   7 - JTAG_UART_BASE:   JTAG connection from PC to core
*   8 - USR_TIMER_BASE:   1uS Timer used to set delays
* </pre>
*
* @author David L. Kempert
*
*/
//********************************************************************************
#include <stdlib.h>
#include <stdio.h>
#include "system.h"
#include "drivers.h"
#include "sd_drivers.h"
#include "pff.h"

static void put_dump(const void* buff, unsigned long addr, int len);

static int xatoi(char **str, long *res);

char Line[128];		/* Console input buffer */

static void put_rc (FRESULT rc)
{
	char *p;
	static const char str[] =
		"OK\0" "DISK_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
		"NOT_OPENED\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0";
	FRESULT i;

	for (p = str, i = 0; i != rc && *p; i++) {
		while(*p++) ;
	}
	printf("rc=%u FR_%S\n", (WORD)rc, p);
}

static void put_drc (BYTE res)
{
	printf("rc=%d\n", res);
}

/*********************************************************************************
* int main(void)
**********************************************************************************/
/**
* @brief  This is the main function called from the HAL initialization framework.
*
* This function starts the application layer that interfaces with the user
* through the debug console and allows FAT16 file access to the SD card.
*
*--------------------------------------------------------------------------------*/
int main (void)
{
  char *ptr;
  long p1, p2;
  BYTE res;
  WORD s1, s2, s3, ofs, cnt, w;
  FATFS fs;			/* File system object */
  DIR dir;			/* Directory object */
  FILINFO fno;		/* File information */

  timer_wr_prd(USR_TIMER_BASE, 50); ///< Set Timer with a 1us timeout period

  printf("\nPFF test monitor\n");

  for (;;) {
    printf(">");             ///< Show command prompt
    gets(Line);       ///< Wait for user to enter a command
    ptr = Line;

    switch (*ptr++) {

      case 'd' :
			  switch (*ptr++) {
			    case 'i' :	/* di - Initialize physical drive */
				    disk_initialize();
				    put_drc(res);
				    break;

			    case 'd' :	// dd <sector> <ofs> - Dump partial sector 128 bytes
				    if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
				    s2 = p2;
				    res = disk_readp((BYTE*)Line, p1, s2, 128);
				    if (res) { put_drc(res); break; }
				    s3 = s2 + 128;
				    for (ptr = Line; s2 < s3; s2 += 16, ptr += 16, ofs += 16) {
					    s1 = (s3 - s2 >= 16) ? 16 : s3 - s2;
					    put_dump((BYTE*)ptr, s2, s1);
				    }
				    break;
			  }
			  break;

      case 'f' :
			  switch (*ptr++) {

			    case 'i' :	/* fi - Mount the volume */
				    put_rc(pf_mount(&fs));
				    break;

			    case 'o' :	/* fo <file> - Open a file */
				    while (*ptr == ' ') ptr++;
				    put_rc(pf_open(ptr));
				    break;
#if _USE_READ
			    case 'd' :	/* fd - Read the file 128 bytes and dump it */
				    ofs = fs.fptr;
				    res = pf_read(Line, sizeof(Line), &s1);
				    if (res != FR_OK) { put_rc(res); break; }
				    ptr = Line;
				    while (s1) {
					    s2 = (s1 >= 16) ? 16 : s1;
					    s1 -= s2;
					    put_dump((BYTE*)ptr, ofs, s2);
					    ptr += 16; ofs += 16;
				    }
				    break;

			    case 't' :	/* ft - Type the file data via dreadp function */
				    do {
					    res = pf_read(0, 32768, &s1);
					    if (res != FR_OK) { put_rc(res); break; }
				    } while (s1 == 32768);
				    break;
#endif
#if _USE_WRITE
			    case 'w' :	/* fw <len> <val> - Write data to the file */
				    if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
				    for (s1 = 0; s1 < sizeof(Line); Line[s1++] = (BYTE)p2) ;
				    p2 = 0;
				    while (p1) {
					    if ((UINT)p1 >= sizeof(Line)) {
						    cnt = sizeof(Line); p1 -= sizeof(Line);
					    } else {
					    	cnt = (WORD)p1; p1 = 0;
					    }
					    res = pf_write(Line, cnt, &w);	/* Write data to the file */
					    p2 += w;
					    if (res != FR_OK) { put_rc(res); break; }
					    if (cnt != w) break;
				    }
				    res = pf_write(0, 0, &w);		/* Finalize the write process */
				    put_rc(res);
				    if (res == FR_OK)
					    printf("%lu bytes written.\n", p2);
				    break;

			    case 'p' :	/* fp - Write console input to the file */
				    printf("Enter lines to write. A blank line finalize the write operation.\n");
				    for (;;) {
              gets(Line);       ///< Wait for user to enter a line
					    if (!Line[0]) break;
					    strcat(Line, "\r\n");
					    res = pf_write(Line, strlen(Line), &w);	/* Write a line to the file */
					    if (res) break;
				    }
				    res = pf_write(0, 0, &w);		/* Finalize the write process */
				    put_rc(res);
				    break;
#endif
#if _USE_LSEEK
			    case 'e' :	/* fe - Move file pointer of the file */
				    if (!xatoi(&ptr, &p1)) break;
				    res = pf_lseek(p1);
				    put_rc(res);
				    if (res == FR_OK)
					    printf("fptr = %lu(0x%lX)\n", fs.fptr, fs.fptr);
				    break;
#endif
#if _USE_DIR
			    case 'l' :	/* fl [<path>] - Directory listing */
				    while (*ptr == ' ') ptr++;
				    res = pf_opendir(&dir, ptr);
				    if (res) { put_rc(res); break; }
				    s1 = 0;
				    for(;;) {
					    res = pf_readdir(&dir, &fno);
					    if (res != FR_OK) { put_rc(res); break; }
					    if (!fno.fname[0]) break;
					    if (fno.fattrib & AM_DIR)
						    printf("   <DIR>   %s\n", fno.fname);
					    else
						    printf("%9lu  %s\n", fno.fsize, fno.fname);
					    s1++;
				    }
				    printf("%u item(s)\n", s1);
				    break;
#endif
			  }
			  break;
    }
	}
}


/*----------------------------------------------*/
/* Dump a line of binary dump                   */
/*----------------------------------------------*/
static void put_dump (
	const void* buff,		/* Pointer to the byte array to be dumped */
	unsigned long addr,		/* Heading address value */
	int len					/* Number of bytes to be dumped */
)
{
	int i;
	unsigned char ch;
	const unsigned char *p = buff;

  printf("0x%08lx ", addr);   /* address */
  for (i=0; i<len; i++)
    printf("%02x ", p[i]);
  printf("  ");
  for (i=0; i<len; i++) {
    ch = p[i];
    if (ch>127 || ch<32) //non ascii
      ch = '.';
    printf ("%c", ch);
  } // end for i
  printf("\n");
}

/*----------------------------------------------*/
/* Get a value of the string                    */
/*----------------------------------------------*/
/*	"123 -5   0x3ff 0b1111 0377  w "
	    ^                           1st call returns 123 and next ptr
	       ^                        2nd call returns -5 and next ptr
                 ^                3rd call returns 1023 and next ptr
                        ^         4th call returns 15 and next ptr
                             ^    5th call returns 255 and next ptr
                                ^ 6th call fails and returns 0
*/

static int xatoi (			/* 0:Failed, 1:Successful */
	char **str,		/* Pointer to pointer to the string */
	long *res		/* Pointer to the valiable to store the value */
)
{
	unsigned long val;
	unsigned char c, r, s = 0;

	*res = 0;

	while ((c = **str) == ' ') (*str)++;	/* Skip leading spaces */

	if (c == '-') {		/* negative? */
		s = 1;
		c = *(++(*str));
	}

	if (c == '0') {
		c = *(++(*str));
		switch (c) {
		case 'x':		/* hexdecimal */
			r = 16; c = *(++(*str));
			break;
		case 'b':		/* binary */
			r = 2; c = *(++(*str));
			break;
		default:
			if (c <= ' ') return 1;	/* single zero */
			if (c < '0' || c > '9') return 0;	/* invalid char */
			r = 8;		/* octal */
		}
	} else {
		if (c < '0' || c > '9') return 0;	/* EOL or invalid char */
		r = 10;			/* decimal */
	}

	val = 0;
	while (c > ' ') {
		if (c >= 'a') c -= 0x20;
		c -= '0';
		if (c >= 17) {
			c -= 7;
			if (c <= 9) return 0;	/* invalid char */
		}
		if (c >= r) return 0;		/* invalid char for current radix */
		val = val * r + c;
		c = *(++(*str));
	}
	if (s) val = 0 - val;			/* apply sign if needed */

	*res = val;
	return 1;
}

