/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright (C) 2014 Renesas Electronics Corporation. All rights reserved.
*******************************************************************************/
/*******************************************************************************
* File Name   : main_thread.c
* Description : Main program
*******************************************************************************/

/******************************************************************************
Includes   <System Includes> , "Project Includes"
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "cmsis_os.h"
#include "r_typedefs.h"
#include "ff.h"
#include "fat_fsi.h"
#include "dec.h"
#include "command.h"
#include "Serial.h"

/******************************************************************************
Typedef definitions
******************************************************************************/
#define MAX_FILE_PATH             0xffu
#define MAX_FILE_NAME             0xffu

typedef struct {
    uint32_t event;
    int32_t  detail;
    uint32_t param;
}msg_main_t;

typedef struct
{
    int32_t     drive;                     /* usb mmemory drive */
    uint32_t    device_address;            /* usb audio device address */
    uint32_t    current_index;             /* current file list index (for playcommand mode) */
    uint32_t    next_index;                /* next file list index (for playcommand mode) */
    FATFS       fat_fs;                    /* work area (file system) */
    FIL         file_pointer;              /* file poiner (file system) */
    uint32_t    mode;                      /* main thread mode */
    uint8_t     file_path[MAX_FILE_PATH];  /* play file path */
} play_info_t;

typedef struct file_list
{
    uint32_t Num;
    uint8_t FileName[MAX_FILE_NAME];
} file_list_t;


/******************************************************************************
Macro definitions
******************************************************************************/
/* ==== MODE ==== */
#define MAIN_MODE_CLOSE         (0UL)
#define MAIN_MODE_OPEN_WAIT     (1UL)
#define MAIN_MODE_OPEN          (2UL)
#define MAIN_MODE_CLOSE_WAIT    (3UL)
#define MAIN_MODE_MAX           (4UL)
#define MAIN_MODE_KEEP          (5UL)
#define MAIN_MODE_ERR           (6UL)

#define BACK_SPACE               0x08u
#define ENTER                    0x0Du
#define SPACE                    0x20u
#define NEW_LINE                 0x0au

#define MAX_MAIN_MAILQ          (8u)

#define FILEPATH_MODE            0x01UL
#define PLAYCOMMAND_MODE         0x02UL

#define MAX_FILE_LIST           (256UL)

#define INIT_TRACK_NUM           0xffffffffUL

#define MAIN_WAIT_TIME           10u

/******************************************************************************
Imported global variables and functions (from other files)
******************************************************************************/
extern bool_t Get_USB_Connect_Info(void);
/******************************************************************************
Exported global variables and functions (to be accessed by other files)
******************************************************************************/
/* Main thread */
void Main_Thread(int32_t DriveNo, uint32_t DevAddr);

osMailQId g_main_mailq_id;
osMailQDef(g_main_mailq, MAX_MAIN_MAILQ, msg_main_t);

/******************************************************************************
Private global variables and functions
******************************************************************************/
/* Sub Main Process */
static void main_manual_play(void);
static void main_auto_play(void);

static uint32_t main_open (play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_play (play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_stop (play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_pause(play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_t_up (play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_t_dwn(play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_next (play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_nextsong(play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_close(play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_err(play_info_t *arg_play_info, msg_main_t *msg);
static uint32_t main_dummy(play_info_t *arg_play_info, msg_main_t *msg);

static uint32_t main_SelectMode(void);
static uint32_t main_get_command(uint32_t chara_data, uint8_t * command_buff, uint8_t *buff_pos);
static FRESULT main_f_mount(int32_t arg_drive, FATFS *fat_fs);
static int32_t main_scan_files (int8_t* path);
static int32_t main_scan_flacfiles (int8_t* path, file_list_t * file_list, uint32_t count);
static int32_t main_check_flacfile(FILINFO *fno);

static int32_t main_cmd_dir(int32_t argc, char_t ** argv);
static int32_t main_cmd_play(int32_t argc, char_t ** argv);
static int32_t main_cmd_stop(int32_t argc, char_t ** argv);
static int32_t main_cmd_pause(int32_t argc, char_t ** argv);
static int32_t main_cmd_trackup(int32_t argc, char_t ** argv);
static int32_t main_cmd_trackdown(int32_t argc, char_t ** argv);

/* ==== Global variable ==== */
static uint8_t main_command_buff[MAX_FILE_PATH];
static uint8_t main_chara_counter;
static uint8_t main_currentdir[MAX_FILE_PATH];
static file_list_t main_file_list[MAX_FILE_LIST];
static play_info_t main_play_info __attribute__ ((section ("NC_DATA")));


/******************************************************************************
* Function Name: MAIN_Create_Main_MailQ
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
int32_t MAIN_Create_Main_MailQ(void)
{
    osEvent      evt;
    msg_main_t   *rptr;
    int32_t ret;

    if (g_main_mailq_id == 0)
    {
        /* create maine mail queue */
        g_main_mailq_id = osMailCreate(osMailQ(g_main_mailq), NULL);
    }
    else
    {
        do
        {
            evt = osMailGet(g_main_mailq_id, 0);
            if (evt.status == osEventMail)
            {
                rptr = evt.value.p;
                (void)osMailFree(g_main_mailq_id, rptr);
            }
        }
        while (evt.status == osEventMail);
    }
    if (g_main_mailq_id != 0)
    {
        ret = 0;
    }
    else
    {
        ret = -1;
    }
    return ret;
}

/*******************************************************************************
* Function Name: MAIN_SndMsg
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
int32_t MAIN_SndMsg (uint32_t event, int32_t detail, uint32_t param)
{
    int32_t    ret = 0;
    msg_main_t *mptr;
    osStatus   os_status;

    mptr = osMailAlloc(g_main_mailq_id, osWaitForever);
    if(mptr != NULL)
    {
        mptr->event = event;
        mptr->detail = detail;
        mptr->param = param;
        os_status = osMailPut(g_main_mailq_id, mptr);
        if (os_status != osOK)
        {
            (void)printf("dec_callback error: osMailPut error %d\n",ret);
            ret = -1;
        }
    }
    else
    {
        ret = -1;
    }

    return ret;
}

/******************************************************************************
* Function Name: Main_Thread
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
void Main_Thread(int32_t DriveNo, uint32_t DevAddr)
{
    static const command_list_t usb_audio_flac_command[] =
    {
        {"DIR",         main_cmd_dir,           NULL},
        {"PLAY",        main_cmd_play,          NULL},
        {"STOP",        main_cmd_stop,          NULL},
        {"PAUSE",       main_cmd_pause,         NULL},
        {"TRACKUP",     main_cmd_trackup,       NULL},
        {"TRACKDOWN",   main_cmd_trackdown,     NULL},
        {NULL,          NULL,                   NULL}
    };

    /* ==== main thead initialize ==== */
    (void)memset(main_command_buff, 0x00, sizeof(main_command_buff));
    (void)memset(main_currentdir, 0x00, sizeof(main_currentdir));
    (void)memset(&main_play_info, 0x00, sizeof(main_play_info));

    main_chara_counter = 0;
    CommandSetCmdList(usb_audio_flac_command);

    /* ==== Select Drive number of USB memory ==== */
    main_play_info.drive = DriveNo;

    /* ==== Select USB Audio device address ==== */
    main_play_info.device_address = DevAddr;

    /* ==== Mount Process ==== */
    if (main_f_mount(main_play_info.drive, &main_play_info.fat_fs) == FR_OK)
    {
        /* ==== Manual play ==== */
        main_manual_play();
    }
    else
    {
        /* DO NOTHING */
    }
}


/******************************************************************************
* Function Name: main_manual_play
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static void main_manual_play(void)
{
    osEvent      evt;
    msg_main_t   *rptr;
    msg_main_t   msg;
    uint32_t     chara_data;

    main_play_info.mode = MAIN_MODE_CLOSE;
    (void)memset(&msg, 0x00, sizeof(msg));
    msg.event = MAIN_EVENT_NONE;

    /* ==== Select Music File ==== */
    (void)printf("Please select music file\n");
    while (Get_USB_Connect_Info() == true)
    {
        /* ==== Get Event ==== */
        evt = osMailGet(g_main_mailq_id, MAIN_WAIT_TIME);
        if (evt.status == osEventMail)
        {
            rptr = evt.value.p;
            msg.event = rptr->event;
            msg.param = rptr->param;
            msg.detail = rptr->detail;
            (void)osMailFree(g_main_mailq_id, rptr);
        }
        /* ==== Timeout proccess ==== */
        else if (evt.status == osEventTimeout)
        {
            chara_data = (uint32_t)SER_GetChar();
            msg.event = main_get_command(chara_data, &main_command_buff[0], &main_chara_counter);
            msg.param = 0;
            msg.detail = DEC_OK;
        }
        else
        {
            /* DO NOTHING */
        }
        /* ==== Sub Main Process ==== */
        switch (msg.event)
        {
        /* Event from terminal */
        case MAIN_EVENT_SPLAY:
            if (main_play_info.mode == MAIN_MODE_CLOSE)
            {
                main_play_info.mode = main_open(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        case MAIN_EVENT_SSTOP:
            if (main_play_info.mode == MAIN_MODE_OPEN)
            {
                main_play_info.mode = main_stop(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        /* Event from decoder thread */
        case MAIN_EVENT_OPEN:
            if (main_play_info.mode == MAIN_MODE_OPEN_WAIT)
            {
                main_play_info.mode = main_play(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        case MAIN_EVENT_PLAY:
            if (main_play_info.mode == MAIN_MODE_OPEN)
            {
                main_play_info.mode = main_dummy(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        case MAIN_EVENT_STOP:
            if (main_play_info.mode == MAIN_MODE_CLOSE_WAIT)
            {
                main_play_info.mode = main_close(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        case MAIN_EVENT_END:
            if (main_play_info.mode == MAIN_MODE_OPEN)
            {
                main_play_info.mode = main_close(&main_play_info, &msg);
            }
            else
            {
                main_play_info.mode = main_err(&main_play_info, &msg);
            }
            break;
        default:
            main_play_info.mode = main_dummy(&main_play_info, &msg);
            break;
        }
        if (msg.event == (uint32_t)MAIN_EVENT_ERR)
        {
            (void)printf("Play Error\n");
            (void)printf("Please detach device\n");
            main_play_info.mode = MAIN_MODE_ERR;
        }
        (void)memset(&msg, 0x00, sizeof(msg));
        msg.event = MAIN_EVENT_NONE;
    }

    /* ==== usb detach proccess ==== */
    (void)printf("Detach device.\n");
    (void)f_close(&main_play_info.file_pointer);
    (void)f_mount(NULL, NULL, 0);
}

/******************************************************************************
* Function Name: main_auto_play
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static void main_auto_play(void)
{
    osEvent      evt;
    msg_main_t   *rptr;
    msg_main_t   msg;
    uint32_t     LoopCount;
    int32_t      ret = true;
    uint32_t     chara_data;

    /* ==== Initialize file list ==== */
    (void)memset(main_file_list, 0x00, sizeof(main_file_list));
    (void)memset(&msg, 0x00, sizeof(msg));
    for (LoopCount = 0; LoopCount < MAX_FILE_LIST; LoopCount++)
    {
        main_file_list[LoopCount].Num = INIT_TRACK_NUM;
    }

    /* ==== Scan file ==== */
    (void)printf("Scan USB Memory start\n");
    if (main_scan_flacfiles (main_currentdir, main_file_list, MAX_FILE_LIST) == 0UL)
    {
        /* ==== Success scan files ==== */
        if (main_file_list[0].Num == INIT_TRACK_NUM)
        {
            (void)printf("No flac file\n");
            ret = false;
        }
        else
        {
            (void)printf("Success scan files\n");
            for (LoopCount = 0;
                (LoopCount < MAX_FILE_LIST) && (main_file_list[LoopCount].Num != INIT_TRACK_NUM);
                LoopCount++)
            {
                (void)printf("%d : %s\n", main_file_list[LoopCount].Num,
                  main_file_list[LoopCount].FileName);
            }
        }
    }
    else
    {
        /* ==== Error scan files ==== */
        (void)printf("Error : scan files\n");
        ret = false;
    }
    if (ret == true)
    {
        /* ==== Play first FLAC file ==== */
        main_play_info.current_index = 0;
        main_play_info.next_index = INIT_TRACK_NUM;
        (void)strcpy(main_play_info.file_path, main_file_list[main_play_info.current_index].FileName);
        main_play_info.mode = main_open(&main_play_info, &msg);
        if (main_play_info.mode != MAIN_MODE_CLOSE)
        {
            while (Get_USB_Connect_Info() == true)
            {
                /* ==== Get Event ==== */
                evt = osMailGet(g_main_mailq_id, MAIN_WAIT_TIME);
                if (evt.status == osEventMail)
                {
                    rptr = evt.value.p;
                    msg.event = rptr->event;
                    msg.param = rptr->param;
                    msg.detail = rptr->detail;
                    (void)osMailFree(g_main_mailq_id, rptr);
                }
                /* ==== timeout proccess ==== */
                else if (evt.status == osEventTimeout)
                {
                    chara_data = (uint32_t)SER_GetChar();
                    /* check command */
                    msg.event = main_get_command(chara_data,
                                                 &main_command_buff[0],
                                                 &main_chara_counter);
                    msg.param = 0;
                    msg.detail = DEC_OK;
                }
                else
                {
                    /* DO NOTHING */
                }
                /* ==== Sub Main Process ==== */
                switch (msg.event)
                {
                /* Event from terminal */
                case MAIN_EVENT_SPLAY:
                    if (main_play_info.mode == MAIN_MODE_CLOSE){
                        main_play_info.mode = main_open(&main_play_info, &msg);
                    }
                    else if (main_play_info.mode == MAIN_MODE_OPEN_WAIT){
                        main_play_info.mode = main_play(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                case MAIN_EVENT_SPAUSE:
                    if (main_play_info.mode == MAIN_MODE_OPEN){
                        main_play_info.mode = main_pause(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                case MAIN_EVENT_STUP:
                    if (main_play_info.mode == MAIN_MODE_OPEN){
                        main_play_info.mode = main_t_up(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                case MAIN_EVENT_STDWN:
                    if (main_play_info.mode == MAIN_MODE_OPEN){
                        main_play_info.mode = main_t_dwn(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                /* Event from decoder thread */
                case MAIN_EVENT_OPEN:
                    if (main_play_info.mode == MAIN_MODE_OPEN_WAIT){
                        main_play_info.mode = main_play(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                case MAIN_EVENT_PLAY:
                    if (main_play_info.mode == MAIN_MODE_OPEN){
                        main_play_info.mode = main_dummy(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                case MAIN_EVENT_STOP:
                    main_play_info.mode = main_close(&main_play_info, &msg);
                    break;
                case MAIN_EVENT_PAUSE:
                    /* DO NOTHING */
                    break;
                case MAIN_EVENT_END:
                    if (main_play_info.mode == MAIN_MODE_OPEN){
                        main_play_info.mode = main_next(&main_play_info, &msg);
                    }
                    else
                    {
                        main_play_info.mode = main_err(&main_play_info, &msg);
                    }
                    break;
                default:
                    main_play_info.mode = main_dummy(&main_play_info, &msg);
                    break;
                }
                if (msg.event == (uint32_t)MAIN_EVENT_ERR)
                {
                    (void)printf("Play Error\n");
                    (void)printf("Please detach device\n");
                    main_play_info.mode = MAIN_MODE_ERR;
                }
                (void)memset(&msg, 0x00, sizeof(msg));
                msg.event = MAIN_EVENT_NONE;
            }
        }
    }

    /* ==== usb detach proccess ==== */
    (void)printf("Detach device.\n");
    (void)f_close(&main_play_info.file_pointer);
    (void)f_mount(NULL, NULL, 0);
}

/******************************************************************************
* Function Name: main_open
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_open(play_info_t *arg_play_info, msg_main_t *msg)
{
    FRESULT   tmp_ret;
    FIL       tmp_file_pointer;
    uint32_t  tmp_mode;
    uint8_t   path[300];
    msg;

#ifdef DEBUG_PRINT
    (void)printf("Open file [%s].\n", arg_play_info->file_path);
#endif

    (void)memset(path, 0, sizeof(path));

    tmp_mode = MAIN_MODE_CLOSE;
    switch (arg_play_info->drive)
    {
    case 0:
        (void)sprintf(path, "0:%s", arg_play_info->file_path);
        tmp_ret = f_open(&tmp_file_pointer, path, FA_READ);
        if (tmp_ret != FR_OK)
        {
            (void)printf("Open file error.\n");
        }
        else
        {
            arg_play_info->file_pointer = tmp_file_pointer;
            /* ==== Docoder Open ==== */
            (void)DEC_Open(arg_play_info->drive,
                           arg_play_info->device_address,
                           &arg_play_info->file_pointer);
            tmp_mode = MAIN_MODE_OPEN_WAIT;
        }
        break;
    default:
        /* DO NOHING */
        break;
    }
    return tmp_mode;
}

/******************************************************************************
* Function Name: main_play
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_play(play_info_t *arg_play_info, msg_main_t *msg)
{
    uint32_t  tmp_mode;

    if (msg->detail == (int32_t)DEC_OK)
    {
        /* ==== Docoder Play ==== */
        (void)DEC_Play(arg_play_info->drive,
                       arg_play_info->device_address,
                       &arg_play_info->file_pointer);
        tmp_mode = MAIN_MODE_OPEN;
    }
    else
    {
        tmp_mode = main_close(arg_play_info, msg);
    }

    return tmp_mode;
}

/******************************************************************************
* Function Name: main_pause
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_pause(play_info_t *arg_play_info, msg_main_t *msg)
{
    uint32_t  tmp_mode;

    if (msg->detail == (int32_t)DEC_OK)
    {
        /* ==== Docoder Pause ==== */
        (void)DEC_Pause(arg_play_info->drive,
                        arg_play_info->device_address,
                        &arg_play_info->file_pointer);
        tmp_mode = MAIN_MODE_OPEN_WAIT;
    }
    else
    {
        tmp_mode = main_close(arg_play_info, msg);
    }

    return tmp_mode;
}

/******************************************************************************
* Function Name: main_stop
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_stop(play_info_t *arg_play_info, msg_main_t *msg)
{
    /* ==== Docoder Stop ==== */
    (void)DEC_Stop(arg_play_info->drive,
                   arg_play_info->device_address,
                   &arg_play_info->file_pointer);

    return MAIN_MODE_CLOSE_WAIT;
}

/******************************************************************************
* Function Name: main_t_up
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_t_up(play_info_t *arg_play_info, msg_main_t *msg)
{
    if (arg_play_info->next_index == INIT_TRACK_NUM)
    {
        arg_play_info->next_index = arg_play_info->current_index + 1;
    }
    else
    {
        arg_play_info->next_index++;
    }
    if (main_file_list[arg_play_info->next_index].Num == INIT_TRACK_NUM)
    {
        arg_play_info->next_index = 0;
    }

    return main_stop(arg_play_info, msg);
}

/******************************************************************************
* Function Name: main_t_dwn
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_t_dwn(play_info_t *arg_play_info, msg_main_t *msg)
{
    if (arg_play_info->next_index == INIT_TRACK_NUM)
    {
        if (arg_play_info->current_index > 0UL)
        {
            arg_play_info->next_index = arg_play_info->current_index - 1;
        }
        else
        {
            arg_play_info->next_index = 0;
        }
    }
    else
    {
        if (arg_play_info->current_index > 0UL)
        {
            arg_play_info->next_index--;
        }
    }

    return main_stop(arg_play_info, msg);
}

/******************************************************************************
* Function Name: main_next
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_next(play_info_t *arg_play_info, msg_main_t *msg)
{
    FRESULT   f_result;

    f_result = f_close(&arg_play_info->file_pointer);
    if (f_result != (int32_t)FR_OK)
    {
        (void)printf("Close file error.\n");
    }
    if (arg_play_info->next_index == INIT_TRACK_NUM)
    {
        arg_play_info->next_index = arg_play_info->current_index + 1;
    }

    return main_nextsong(arg_play_info, msg);
}

/******************************************************************************
* Function Name: main_nextsong
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_nextsong(play_info_t *arg_play_info, msg_main_t *msg)
{
    uint32_t  tmp_mode;

    if (msg->detail == DEC_OK)
    {
        if (main_file_list[arg_play_info->next_index].Num == INIT_TRACK_NUM)
        {
            arg_play_info->next_index= 0;
        }

        (void)strcpy(arg_play_info->file_path, main_file_list[arg_play_info->next_index].FileName);
        arg_play_info->current_index = arg_play_info->next_index;
        arg_play_info->next_index = INIT_TRACK_NUM;

        tmp_mode = main_open(arg_play_info, msg);
    }
    else
    {
        tmp_mode = main_close(arg_play_info, msg);
    }

    return tmp_mode;
}

/******************************************************************************
* Function Name: main_close
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_close(play_info_t *arg_play_info, msg_main_t *msg)
{
    uint32_t  tmp_mode;
    FRESULT   f_result;

    tmp_mode = MAIN_MODE_CLOSE;
    f_result = f_close(&arg_play_info->file_pointer);
    if (f_result != FR_OK)
    {
        (void)printf("Close file error.\n");
    }

    (void)printf("Please select music file\n");

    return tmp_mode;
}

/******************************************************************************
* Function Name: main_err
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_err(play_info_t *arg_play_info, msg_main_t *msg)
{
    (void)printf("Error event mode:%x event:%x\n", arg_play_info->mode, msg->event);
    return arg_play_info->mode;
}

/******************************************************************************
* Function Name: main_dummy
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_dummy(play_info_t *arg_play_info, msg_main_t *msg)
{
    return arg_play_info->mode;
}

/******************************************************************************
* Function Name: main_SelectMode
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_SelectMode(void)
{
    int32_t  play_mode;

    (void)printf("Please select Play Mode (1:FilePath 2:PlayCommand):");
    (void)scanf("%d", &play_mode);
    (void)printf("\n");

    if (play_mode == FILEPATH_MODE)
    {
        (void)printf("Play Mode : File Path\n");
    }
    else if (play_mode == PLAYCOMMAND_MODE)
    {
        (void)printf("Play Mode : Play Command\n");
    }
    else
    {
        (void)printf("ERROR : \n", play_mode);
    }

    return play_mode;
}

/******************************************************************************
* Function Name: main_f_mount
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static FRESULT main_f_mount(int32_t arg_drive, FATFS *fat_fs)
{
    FRESULT  f_result = FR_INVALID_PARAMETER;

    switch (arg_drive)
    {
    case 0:
        f_result = f_mount(fat_fs,"0:", 1);
        if (f_result != FR_OK)
        {
            (void)printf("ERROR : mount USB drive %d\n", arg_drive);
        }
        break;
    default:
        (void)printf("ERROR : mount USB drive %d\n", arg_drive);
        break;
    }

    return f_result;
}

/******************************************************************************
* Function Name: main_get_command
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static uint32_t main_get_command(uint32_t chara_data, uint8_t * command_buff, uint8_t *buff_pos)
{
    uint32_t commnad_id = MAIN_EVENT_NONE;
    int32_t ret;
    uint32_t count = (uint32_t)*buff_pos;

    if ((chara_data >= ' ') && (chara_data <= '~'))
    {
        (void)SER_PutChar(chara_data);
        command_buff[count] = chara_data;
        count++;
    }
    /* Check backspace key */
    else if (chara_data == (uint32_t)BACK_SPACE)
    {
        if (count != 0)
        {
            (void)SER_PutChar(BACK_SPACE);
            (void)SER_PutChar(SPACE);
            (void)SER_PutChar(BACK_SPACE);
            count--;
            command_buff[count] = '\0';
        }
    }
    /* Check enter key */
    else if (chara_data == (uint32_t)ENTER)
    {
        (void)SER_PutChar(NEW_LINE);
        (void)SER_PutChar(ENTER);
        command_buff[count] = '\0';

        ret = CommandExe(command_buff);
        if ((ret == COMMAND_SUCCESS)
          || (ret == COMMAND_EXIT)
          || (ret == COMMAND_ERROR))
        {
            commnad_id = MAIN_EVENT_NONE;
        }
        else
        {
            commnad_id = (uint32_t)ret;
        }
        count = 0;
    }
    else
    {
        /* DO NOTHING */
    }
    *buff_pos = count;
    return commnad_id;
}

/*******************************************************************************
* Function Name: main_cmd_dir
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_dir (int32_t argc, char_t ** argv)
{
    (void)main_scan_files (main_currentdir);
    return MAIN_EVENT_NONE;
}

/*******************************************************************************
* Function Name: main_cmd_play
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_play (int32_t argc, char_t ** argv)
{
    uint8_t * path = argv[1];

    (void)sprintf(&main_play_info.file_path[0], "%s%s", main_currentdir, path);

    return MAIN_EVENT_SPLAY;
}

/*******************************************************************************
* Function Name: main_cmd_stop
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_stop (int32_t argc, char_t ** argv)
{
    uint8_t * path = argv[1];

    if ((uint32_t)path[0] != '\0')
    {
        (void)printf("Command error\n");
        return MAIN_EVENT_NONE;
    }
    else
    {
        return MAIN_EVENT_SSTOP;
    }
}

/*******************************************************************************
* Function Name: main_cmd_pause
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_pause (int32_t argc, char_t ** argv)
{
    uint8_t * path = argv[1];

    if ((uint32_t)path[0] != '\0')
    {
        (void)printf("Command error\n");
        return MAIN_EVENT_NONE;
    }
    else
    {
        return MAIN_EVENT_SPAUSE;
    }
}

/*******************************************************************************
* Function Name: main_cmd_trackup
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_trackup (int32_t argc, char_t ** argv)
{
    uint8_t * path = argv[1];

    if ((uint32_t)path[0] != '\0')
    {
        (void)printf("Command error\n");
        return MAIN_EVENT_NONE;
    }
    else
    {
        return MAIN_EVENT_STUP;
    }
}

/*******************************************************************************
* Function Name: main_cmd_trackdown
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_cmd_trackdown (int32_t argc, char_t ** argv)
{
    uint8_t * path = argv[1];

    if ((uint32_t)path[0] != '\0')
    {
        (void)printf("Command error\n");
        return MAIN_EVENT_NONE;
    }
    else
    {
        return MAIN_EVENT_STDWN;
    }
}

/*******************************************************************************
* Function Name: main_scan_files
* Description  : 
* Argument     : 
* Return Value : 
*******************************************************************************/
static int32_t main_scan_files (int8_t* path)
{
    int32_t Result = 0;

    FRESULT f_result;
    FILINFO fno;
    DIR dir;

    f_result = f_opendir(&dir, path);
    if (f_result == FR_OK)
    {
        (void)f_readdir(&dir, NULL);
        do
        {
            f_result = f_readdir(&dir, &fno);
            if ((f_result != FR_OK) || (fno.fname[0] == 0UL))
            {
                /* DO NOTHING */
            }
            else
            {
                if (fno.fname[0] == (int32_t)'.')
                {
                         /* DO NOTHING */
                }
                else
                {
                    if (fno.fattrib & AM_DIR)
                    {
                        (void)printf("%s/\n", fno.fname);
                    }
                    else
                    {
                        (void)printf("%s\n", fno.fname);
                    }
                }
            }
        }
        while ((f_result == FR_OK) && (fno.fname[0] != 0UL));
        (void)f_closedir(&dir);
    }
    if (f_result == FR_OK)
    {
        Result = 0;
    }
    else
    {
        Result = -1;
    }

    return Result;
}

/******************************************************************************
* Function Name: main_scan_flacfiles
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
int32_t main_scan_flacfiles (int8_t* path, file_list_t * file_list, uint32_t count)
{
    int32_t result = 0;
    FRESULT f_result;
    FILINFO fno;
    DIR dir;
    uint32_t search_count = 0;

    (void)memset (&fno, 0x00, sizeof(fno));

    f_result = f_opendir(&dir, path);
    if (f_result == FR_OK)
    {
        (void)f_readdir(&dir, NULL);
        do
        {
            f_result = f_readdir(&dir, &fno);
            if ((f_result != FR_OK) || (fno.fname[0] == 0UL))
            {
                /* DO NOTHING */
            }
            else
            {
                if (fno.fname[0] == (int32_t)'.')
                {
                    /* DO NOTHING */
                }
                else
                {
                    if (main_check_flacfile(&fno) == true)
                    {
                        (void)strcpy(file_list[search_count].FileName, fno.fname);
                        file_list[search_count].Num = search_count;
                        search_count++;
                    }
                }
            }
        }
        while ((f_result == FR_OK) && (fno.fname[0] != 0) && (search_count < count));
        (void)f_closedir(&dir);
    }
    if (f_result == FR_OK)
    {
          result = 0;
    }
    else
    {
          result = -1;
    }
    return result;
}

/******************************************************************************
* Function Name: main_check_flacfile
* Description  : 
* Arguments    : 
* Return Value : 
******************************************************************************/
static int32_t main_check_flacfile(FILINFO *fno)
{
    int32_t ret;
    uint32_t loopcount;

    if (fno->fattrib & AM_DIR)
    {
        ret = false;
    }
    else
    {
        for (loopcount = 0UL; loopcount < 10UL; loopcount++)
        {
            if (fno->fname[loopcount] == '.')
            {
                loopcount++;
                break;
            }
        }
        if ((strncmp(&fno->fname[loopcount], "fla", 3) == 0)
            || (strncmp(&fno->fname[loopcount], "FLA", 3) == 0))
        {
            ret = true;
        }
        else
        {
            ret = false;
        }
    }

    return ret;
}

/* End of File */

