/*----------------------------------------------------------------------*/
/* usblWavAudio.c - wav audio output sample with MatrixQuestUSB/lite.   */
/*                                                                      */
/* Copyright 2011 TEPCO UQUEST, LTD.                                    */
/* FatFs sample project for generic microcontrollers (C)ChaN, 2010      */
/*----------------------------------------------------------------------*/

/*
HISTORY
-------
1.0.0a 2011/04/11,ssa  modefied from main.c in FatFs sample for generic.
*/

/*----- include -----*/

#include <stdio.h>
#include "ff.h"
#include "ffconf.h"
#include "integer.h"
#include "diskio.h"
#include "usblFatFsSmp.h"
#include "iodefine.h"

/*----- forward decralations -----*/

DSTATUS demoInit( void ) ;        /* デモ初期化関数                  */
FRESULT ff_main (void);           /* メインプログラム                */
void    usblCMT2Init(void);       /* CMT2の初期化                    */
void    usblAudioDmaInit(void);   /* オーディオ再生のDMAの初期化     */
void    usblDACInit(void);        /* DACの初期化                     */
INT     usblCheckDmaStatus(void); /* 再生中のバッファを示す          */
void    usblStartDMA(void);       /* DMA転送開始                     */
void    usblStopDMA(void);        /* DMA転送停止                     */

LONG buffptr[2];                  /* データバッファのアドレスを保存  */

/*----- externs -----*/

extern void k_taskCreate();
extern void k_taskDelay();

/*----- defines -----*/

#define BUF_SIZE        (2048)    /* トータルのバッファサイズ2kbytes */
#define BUF_SIZE_HALF   (1024)    /* バッファ0/1のサイズはBUF_SIZE/2 */
#define WAV_H_SIZE      (46)      /* WAVヘッダのサイズ               */
#define FOR_USBL        (1)       /* USB(USB/lite)がバッファを使用中 */
#define FOR_DAC         (2)       /* DACがバッファ内を再生中         */
#define FILENAME "TESTDATA.WAV"   /* 再生するファイル名              */


/*************************************************************************
 user_main - ユーザ起動ルーチン OS起動時に実行されます。

 解説
    戻り値を０にするとデモプログラムが起動します。
    戻り値を０以外にするとshellが使用できます。

*/

INT user_main() 
{
#if 0
    return (0); /* サンプルを起動します */
#else
    return (1); /* shellを起動します */
#endif
}

/*-----------------------------------------------------------------------*/
/* Program Initialization.                                               */
/*-----------------------------------------------------------------------*/
/*************************************************************************
 demoInit - デモプログラムの初期化

 解説
        USBを初期化し、使用するバッファ、CMT2,DAC/DMAC0の機能を初期化し
        メインプログラムを実行します。
*/
DSTATUS demoInit( void ) 
{
    INT result;
    FRESULT fresult;

    /* LED初期化 */
    PORT1.DR.BIT.B5  = 1;   /* P15 'H' */
    PORT1.DDR.BIT.B5 = 1;   /* P15出力 */


    /* USBの初期化 */
    result = usblBlkDrv(USBL_TASK_PRI,usblFfInsert,usblFfRemove);
    if ( result != K_OK ) {
        return (RES_ERROR);
    }

    /* バッファアドレスの指定 */
    buffptr[0] = 0x0000F800;        /* BUFFセクションの先頭1kbytes */
    buffptr[1] = 0x0000FC00;        /* BUFFセクションの後半1kbytes */

    usblCMT2Init();                 /* CMT2の初期化 */
    usblDACInit();                  /* DACの初期化 */
    usblAudioDmaInit();             /* オーディオ再生のDMAの初期化 */

    fresult = ff_main();            /* WAVファイルデータ再生メインプログラム */

    if (fresult != FR_OK) {
        return (RES_ERROR);
    }
    return (RES_OK);
}

/*-----------------------------------------------------------------------*/
/* Program Main                                                          */
/*-----------------------------------------------------------------------*/

/************************************************************************
 ff_main --- メインプログラム

 戻り値
        FR_OK 正常終了
 解説
        wavファイルを再生します。
        詳細は本誌記事を参照してください。
*/
FRESULT ff_main (void)
{
    FRESULT rc; /* Result code */
    FATFS fatfs;            /* File system object */
    FIL fil;                /* File object */
    UINT br;
    UINT side;
    UINT count;
    WORD *tmpptr_w;

    f_mount(0, &fatfs);     /* Register volume work area (never fails) */

    printf("\nOpen a test file (wavfile).\n");
    do {
        k_taskDelay(1);
        rc = f_open(&fil, FILENAME, FA_READ);
    } while (rc != FR_OK);

    printf("\nSKIP the wav header.\n");

    tmpptr_w = (WORD *)buffptr[0];

    /* WAVヘッダ部を読み飛ばします */
    rc = f_read(&fil, tmpptr_w , WAV_H_SIZE, &br);

    /* 一旦メモリをクリアします */
    memset ( tmpptr_w,0,WAV_H_SIZE);

    printf("\nPLAY the wav file.(%s)\n",FILENAME);

    /* 2面分のデータを読み込みます */
    for (side=0;side<=1;side++){
        tmpptr_w = (WORD *)buffptr[side];

        /* 0/1両面にUSBメモリからデータを読み込む         */
        /* バッファが埋まらないファイルは再生できません。 */
        rc = f_read(&fil, tmpptr_w, BUF_SIZE_HALF, &br); 
        if (rc || !br) {
            printf("\nERROR too small wav file.\n");
            f_close(&fil);
            return (FR_INVALID_OBJECT);
        }

        /* 2の補数表記を0x0000〜0xffffに変更します */
        for ( count=0 ; count<BUF_SIZE_HALF ; count +=2 ){
            *tmpptr_w += 0x8000; 
            tmpptr_w ++;
        }
    }
    
    usblStartDMA(); /* DMA転送開始 */

    for (;;) {
        for (side=0;side<=1;side++){
            while( usblCheckDmaStatus() == side );

            tmpptr_w = (WORD *)buffptr[side];

            /* 0 or 1面にUSBメモリからデータを読み込む */
            rc = f_read(&fil, tmpptr_w, BUF_SIZE_HALF, &br);

            if (rc || !br) break;       /* Error or end of file */

            /* 2の補数表記を0x0000〜0xffffに変更します */
            for ( count=0 ; count<BUF_SIZE_HALF ; count +=2 ){
                *tmpptr_w += 0x8000;
                tmpptr_w ++;
            }
        }
        if (rc || !br) break;           /* Error or end of file */
    }
    if (rc!=FR_OK) {
        printf("Failed with rc=0x%x.\n", rc);
    }

    usblStopDMA(); /* DMA転送停止 */
    printf("\nClose the file.\n");

    rc = f_close(&fil);
    if (rc!=FR_OK) {
        printf("Failed with rc=0x%x.\n", rc);
    }
    return (rc); 
}


/************************************************************************
 usblCMT2Init --- CMT2の初期化

 解説
        CMT2を初期化します。
        スタンバイを解除し88.2kHzのコンペアマッチ割込みを設定します。
        カウンタの開始はusblStartDMA()で行います。
*/
void usblCMT2Init(void)
{

    SYSTEM.MSTPCRA.BIT.MSTPA14 = 0;     /* スタンバイ解除           */
    CMT2.CMCR.BIT.CKS = 0;              /* PCLK/8を供給             */
    CMT2.CMCR.BIT.CMIE = 1;             /* コンペアマッチ割込み許可 */
    CMT2.CMCOR = 68;                    /* 約88.2kHzの周波数        */

    return;
}

/************************************************************************
 usblAudioDmaInit --- DMAC0の初期化

 解説
        DMAC0を初期化します。
        DMAフリーランノーマル転送モードと拡張リピートモードを組み合わせて
        使用します。
*/
void usblAudioDmaInit(void)
{

    SYSTEM.MSTPCRA.BIT.MSTPA28 = 0;     /* スタンバイ解除           */
    DMAC0.DMCNT.BIT.DTE = 0;            /* 割込み禁止               */

    ICU.DMRSR0= 30;      /* 起動要因の選択 CMT2の割込みとつなぐ     */

    DMAC0.DMSAR = (void *)buffptr[0];   /* バッファのアドレス       */
    DMAC0.DMDAR = (void *)0x000880C0;   /* DACのアドレス            */
    DMAC0.DMTMD.BIT.DCTG = 1;           /* CMT2からの割込み         */
    DMAC0.DMTMD.BIT.SZ = 1;             /* データ転送サイズビット   */
    DMAC0.DMTMD.BIT.DTS = 2;            /* 設定しない               */
    DMAC0.DMTMD.BIT.MD = 0;             /* ノーマル転送             */
    DMAC0.DMCRA = 0x0000;               /* ノーマル転送             */
    DMAC0.DMINT.BYTE = 0;               /* 割込みは使用しない       */
    DMAC0.DMAMD.BIT.DARA = 2;           /* 2bytesの繰り返し         */
    DMAC0.DMAMD.BIT.DM = 2;             /* インクリメント           */
    DMAC0.DMAMD.BIT.SARA = 0xB;         /* 2kbytesの繰り返し        */
    DMAC0.DMAMD.BIT.SM = 2;             /* インクリメント           */
    DMAC0.DMREQ.BYTE = 0;               /* 使用しない               */
    DMAC0.DMSTS.BYTE = 0;               /* 使用しない               */
    DMAC0.DMCNT.BIT.DTE = 0;            /* 初期値は禁止             */
    DMAC0.DMCSL.BIT.DISEL = 0;          /* CPUへは割込みしない      */

    DMAC.DMAST.BIT.DMST =1;             /* DMACA起動を許可          */
    DMAC0.DMCNT.BIT.DTE = 1;            /* 割込み許可               */

    return;
}

/************************************************************************
 usblDACInit --- DACの初期化

 解説
        DACを初期化します。
        LR出力の初期値を０に設定します。
        10bitは上位を有効にします。
*/
void usblDACInit(void)
{

    SYSTEM.MSTPCRA.BIT.MSTPA19 = 0;     /* DAスタンバイ解除         */
    PORT0.DDR.BIT.B3 = 0;               /* DA0出力使用              */
    PORT0.DDR.BIT.B5 = 0;               /* DA1出力使用              */
    DA.DADR0 = 0x8000;                  /* Fix to zero              */
    DA.DADR1 = 0x8000;                  /* Fix to zero              */
    DA.DADPR.BIT.DPSEL = 1;             /* MSB詰め                  */
    DA.DACR.BYTE = 0xFF;                /* D-A変換開始              */

    return;
}

/************************************************************************
 usblStartDMA --- DMAの開始

 解説
        CMT2のカウントを開始します。
        DMAへの割込みを許可しDACへのDMAを開始します。
*/
void usblStartDMA(void)
{

    CMT.CMSTR1.BIT.STR2 = 1;            /* カウント開始             */
    ICU.IER[03].BIT.IEN6 = 1;           /* 割込み許可               */

    return;
}

/************************************************************************
 usblStopDMA --- DMAの停止

 解説
        DMAへの割込みを禁止しDACへのDMAを停止します。
        CMT2のカウントを停止します。
*/
void usblStopDMA(void)
{

    ICU.IER[03].BIT.IEN6 = 0;           /* 割込み禁止               */
    CMT.CMSTR1.BIT.STR2 = 0;            /* カウント停止             */

    return;
}

/************************************************************************
 usblCheckDmaStatus --- DMAの状態確認

 解説
    DMAC0のDMSARを確認し、再生中のバッファを検出します。
 戻り値
    0 DMAはbuff0の領域を再生中
    1 DMAはbuff1の領域を再生中
*/
INT     usblCheckDmaStatus(void)
{

    if ( (LONG)DMAC0.DMSAR >= (LONG)(buffptr[1]) )
    {
        return (1); /* DMAはbuff1の領域を再生中 */
    }
    return (0); /* DMAはbuff0の領域を再生中 */
}

/*---------------------------------------------------------*/
/* User Provided Timer Function for FatFs module           */
/*---------------------------------------------------------*/

DWORD get_fattime (void)
{
    return    ((DWORD)(2010 - 1980) << 25)  /* Fixed to Jan. 1, 2010 */
            | ((DWORD)1 << 21)
            | ((DWORD)1 << 16)
            | ((DWORD)0 << 11)
            | ((DWORD)0 << 5)
            | ((DWORD)0 >> 1);
}

