/*******************************************************************************
MPLAB Harmony Application Source File
Company:
Microchip Technology Inc.
File Name:
app.c
Summary:
This file contains the source code for the MPLAB Harmony application.
Description:
This file contains the source code for the MPLAB Harmony application. It
implements the logic of the application's state machine and it may call
API routines of other MPLAB Harmony modules in the system, such as drivers,
system services, and middleware. However, it does not call any of the
system interfaces (such as the "Initialize" and "Tasks" functions) of any of
the modules in the system or make any assumptions about when those functions
are called. That is the responsibility of the configuration-specific system
files.
*******************************************************************************/
// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved.
Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).
You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.
SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*******************************************************************************/
// DOM-IGNORE-END
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include <proc/p32mz2048efh100.h>
#include "app.h"
#include "stdio.h"
int delay_Clock = 200000000; //システムクロック:200MHz
char Buf[32];
char Buf2[32]; //液晶上段、下段のバッファを分ける //下段が16文字を超えると上段の表示に影響がある
int BtnEvent[2];
int totalFiles;
int ysPlay;
SYS_FS_HANDLE ys_fileHandle;
SYS_FS_HANDLE ys_dirHandle;
SYS_FS_FSTAT ys_dirstat; //ファイル・ディレクトリ構造体
static DISK_FILE_NODE rootNode;
static DISK_FILE_PATH FilesTable[DISK_MAX_FILES];
char str_FileName[64]; //ファイル名
int Num_File = 1;
enum{ //USBの状態に係る列挙名
USB_STATE_OPEN_HOST_LAYER,
USB_STATE_WAIT_FOR_HOST_ENABLE,
USB_STATE_DEVICE_CONNECTED,
USB_STATE_WAIT_FOR_DEVICE_ATTACH,
USB_STATE_UNMOUNT_DISK
}UsbState;
enum{ //USBディスクの状態に係る列挙名
DISK_STATE_INIT,
DISK_STATE_SCAN_FINISHED,
DISK_STATE_OPEN_FIRST_FILE,
DISK_STATE_SCANNING,
DISK_STATE_RUNNING,
DISK_STATE_REMOVED,
DISK_STATE_NO_FILES,
}DiskState;
enum {
APP_OPE_PAUSE_REPLAY = 1,
APP_OPE_SKIP,
}AppBtn;
enum
{
PLAYER_CMD_STOP,
PLAYER_CMD_PLAY,
PLAYER_CMD_NEXT_FILE,
}PlayerCommand;
//関数のプロトタイプ宣言
void DISK_NextTrack(void);
void DISK_CloseTruck (SYS_FS_HANDLE fileHandle);
void DISK_OpenTrack ( const char *fname );
bool ys_FileType83(char *myFileName);
void DISK_TraverseAllFiles(DISK_FILE_NODE node);
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t context);
USB_HOST_EVENT_RESPONSE APP_USBHostEventHandler (USB_HOST_EVENT event, void * eventData, uintptr_t context);
void USB_Connection_Tasks(void);
void DISK_Tasks(void);
void APP_PlayerTask(void);
bool APP_PlayerCommand (int cmd);
void APP_OnButtonEvent(uint8_t button, bool bButtonClosed, int32_t repeatCount);
void APP_BtnTask(void);
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
count = (int)(delay_Clock/20000000)*usec;
do //実測 at 200MH (Clock=200000000)
{ //delay_us(1000):1000.4μsec delay_us(100):100.6μsec delay_us(10):10.5μsec delay_us(1):1.5μsec
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
count--;
}while(count != 0);
}
void delay_ms(volatile unsigned int msec) //1msec遅延
{
volatile unsigned int i; //実測:at200MH (Clock=200000000)//delay_ms(1): 1.0006msec delay_ms(100):100.04msec
for(i=0; i<msec; i++)
delay_us(1000);
}
void Write_Byte(char chr) //1バイト送信関数
{
PLIB_USART_TransmitterByteSend(USART_ID_6, chr); //送信バッファーに1バイト書込み・送信
// U6TXREG = chr; ////送信バッファーに1バイト書込み・送信
while (!PLIB_USART_TransmitterIsEmpty(USART_ID_6)); //送信バッファーが空になるまで待つ
//while(!U6STAbits.TRMT); //送信バッファーが空になるまで待つ
}
void WriteString(const char *str) //文字列送信関数
{
while(*str)
{
Write_Byte(*str); //データ送信
str++;
}
}
void DISK_NextTrack(void) //次のファイル曲へ
{
Num_File++;
if(Num_File > (totalFiles -1))Num_File = 1;
DISK_OpenTrack(FilesTable[Num_File].path); //ファイルオープン
}
void DISK_CloseTruck (SYS_FS_HANDLE fileHandle)
{
SYS_FS_FileClose ( fileHandle );
ysPlay = 0;
LATGbits.LATG15 = 0; //LED1 消灯
}
//ファイルオープン
void DISK_OpenTrack ( const char *fname )
{
char tempBuf[16];
ys_fileHandle = SYS_FS_FileOpen(fname, (SYS_FS_FILE_OPEN_READ_PLUS)); //読み込みモードで、ファイルオープン、
ysPlay = 1;
LATGbits.LATG15 = 1; //LED1 点灯
SYS_FS_FileNameGet(ys_fileHandle, str_FileName, 32 ); //ファイル名取得
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"%s ", str_FileName);//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"%s ", str_FileName + 16);//str_FileName のポインタを16バイト進める
lcd_str(Buf); // 開始メッセージ1行目表示
}
bool ys_FileType83(char *myFileName) //8.3形式ファイルチェック //8.3形式ならtrue
{
bool Flag;
if(myFileName[6] != 0x7E) Flag = true; //~が含まれない → 8.3形式ファイル名
else Flag = false; //~が含まれる → ロングファイル名 //例:MOONRI~1.mp3
return Flag;
}
void DISK_TraverseAllFiles(DISK_FILE_NODE node) //全ファイル詳細調査関数
{
SYS_FS_RESULT ret;
bool Flag83;
char longFileName[300];
char *lfname = node.path;
ys_dirHandle = SYS_FS_DirOpen(lfname); //lfname: フルパスのディレクトリ名 //ルートディレクトリは0
//このdo ループで トータルのファイル数をカウントする。
do
{
if(totalFiles < DISK_MAX_FILES) //DISK_MAX_FILES = 80
{
ys_dirstat.lfname = longFileName;
ys_dirstat.lfsize = 300;
ret = SYS_FS_DirRead(ys_dirHandle,&ys_dirstat); //ディレクトリ・ファイルのステータスを読み込む
//読み込度に 順次異なるディレクトリorファイルを読み込む
//諸元は構造体SYS_FS_FSTATのオブジェクトys_dirstatによる
if ((ys_dirstat.lfname[0] == '\0') && (ys_dirstat.fname[0] == '\0')) //ディレクトリの終端に達した場合、ここで抜ける
{
break;
}
if(ret!= SYS_FS_RES_FAILURE) //読み込み成功なら
{
if(ys_dirstat.fattrib != SYS_FS_ATTR_DIR) // 属性がディレクトリでない場合 //SYS_FS_ATTR_DIR: ディレクトリ
{
Flag83 = ys_FileType83(ys_dirstat.fname);
//8.3形式ファイルの場合
if(Flag83 == true)
{
strcpy(FilesTable[totalFiles].path, lfname); //ファイル名fnameを FilesTable[totalFiles].pathにコピー
strcat(FilesTable[totalFiles].path, ys_dirstat.fname);
(totalFiles)++;
}
//ロングファイル名のファイルの場合
else if(Flag83 != true)
{
strcpy(FilesTable[totalFiles].path, lfname); //ファイル名fnameを FilesTable[totalFiles].pathにコピー
strcat(FilesTable[totalFiles].path, ys_dirstat.lfname);
(totalFiles)++;
}
}
}
}
}while(ret==SYS_FS_RES_SUCCESS);
SYS_FS_DirClose(ys_dirHandle);
}
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t context) //USBマウントに係るコールバック関数
{
switch(event)
{
case SYS_FS_EVENT_MOUNT: //マウント完了の場合
UsbState = USB_STATE_DEVICE_CONNECTED; //USBメモリ接続完了
break;
case SYS_FS_EVENT_UNMOUNT: //未マウントの場合
UsbState = USB_STATE_UNMOUNT_DISK;
UsbState = USB_STATE_WAIT_FOR_DEVICE_ATTACH;
ys_fileHandle = SYS_FS_HANDLE_INVALID;
totalFiles = 0;
break;
default:
break;
}
}
USB_HOST_EVENT_RESPONSE APP_USBHostEventHandler (USB_HOST_EVENT event, void * eventData, uintptr_t context)
{
switch(event)
{
case USB_HOST_EVENT_DEVICE_UNSUPPORTED:
break;
default:
break;
}
return (USB_HOST_EVENT_RESPONSE)USB_HOST_EVENT_RESPONSE_NONE;
}
void USB_Connection_Tasks(void) //USB接続状態
{
switch(UsbState)
{
case USB_STATE_OPEN_HOST_LAYER:
/* Set the event handler and enable the bus */
SYS_FS_EventHandlerSet(APP_SYSFSEventHandler, (uintptr_t)NULL); //コールバック関数APP_SYSFSEventHandler()セット
USB_HOST_EventHandlerSet(APP_USBHostEventHandler, 0); //コールバック関数APP_USBHostEventHandler()セット
// enable, open, bus 0
USB_HOST_RESULT ret = USB_HOST_BusEnable(0);
if(ret == USB_HOST_RESULT_FALSE)
return;
UsbState = USB_STATE_WAIT_FOR_HOST_ENABLE;
break;
case USB_STATE_WAIT_FOR_HOST_ENABLE: //ホストの準備完了待ち
/* Check if the host operation has been enabled */
if(USB_HOST_BusIsEnabled(0))
{
/* This means host operation is enabled. We can
* move on to the next state */
UsbState = USB_STATE_WAIT_FOR_DEVICE_ATTACH;
}
break;
case USB_STATE_WAIT_FOR_DEVICE_ATTACH: //デバイスの接続待ち
/* Wait for device attach. The state machine will move
* to the next state when the attach event
* is received. */
break;
default:
break;
}
}
void DISK_Tasks(void)
{
int i;
USB_Connection_Tasks();
if(UsbState == USB_STATE_DEVICE_CONNECTED) //USBデバイス接続状態
{
//ディスクが抜かれていた場合 → ディスクをスキャンしてリスト作成
if (DiskState == DISK_STATE_REMOVED ) //ファイルなし //ファイルシステムアンマウント //ディスク抜き出し状態
{
DiskState = DISK_STATE_INIT; //ディスクをスキャンしてリスト作成
}
}
else //
{
if ( DiskState != DISK_STATE_REMOVED ) //ディスク抜き出し状態ではない状態
{
DiskState = DISK_STATE_REMOVED;
}
}
switch (DiskState)
{
//PIC起動後 最初に呼ばれる --> ディスクの全スキャン (ファイルの フルパス付きファイル名リストテーブルを作成する)
case DISK_STATE_INIT:
DiskState = DISK_STATE_SCANNING;
break;
case DISK_STATE_SCANNING: //スキャン実行
DISK_TraverseAllFiles(rootNode); //ルートディレクトリの全ファイルを調査する
if(totalFiles == 0)
{
// No File
DiskState = DISK_STATE_NO_FILES;
}
else
{
DiskState = DISK_STATE_SCAN_FINISHED;
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"TotalFile=%d ", (totalFiles - 1)); //FilesTable[0].pathは、System Volume Information
lcd_str(Buf); // 開始メッセージ1行目表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(3000);
//全ファイル表示 for キャラクタ液晶 & UART
for (i = 1; i < totalFiles; i++ ) //FilesTable[0].pathはSystem Volume Information
{
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"%s ", FilesTable[i].path); //
lcd_str(Buf); // 開始メッセージ1行目表示
WriteString(Buf); //UARTへ送信
WriteString("\r\n"); //改行
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf2,"%s ", FilesTable[i].path + 16); //FilesTable[i]のポインタを16バイト進める
lcd_str(Buf2); // 開始メッセージ1行目表示
delay_ms(2000);
}
}
break;
case DISK_STATE_SCAN_FINISHED: //スキャン終了
DiskState = DISK_STATE_OPEN_FIRST_FILE;
break;
case DISK_STATE_OPEN_FIRST_FILE: //最初に呼ばれるファイル
Num_File = 1; //ファイルテーブル No = 1 を設定 //No = 0 にはファイルではないもの(System Volume Information)が入っている
DISK_OpenTrack(FilesTable[Num_File].path); //ファイルオープン
DiskState = DISK_STATE_RUNNING;
break;
case DISK_STATE_RUNNING: //ファイルを繰り返し実行
break;
default:
break;
}
}
bool APP_PlayerCommand (int cmd)
{
switch (cmd)
{
case PLAYER_CMD_STOP:
DISK_CloseTruck(ys_fileHandle);
break;
case PLAYER_CMD_PLAY:
DISK_OpenTrack(FilesTable[Num_File].path); //同じファイルをファイルオープン
break;
case PLAYER_CMD_NEXT_FILE: //スキップ
DISK_CloseTruck(ys_fileHandle); //ファイルを閉じる
DISK_NextTrack (); //次のファイルを開く
break;
default:
break;
}
return ( true );
}
void APP_OnButtonEvent(uint8_t button, bool bButtonClosed, int32_t repeatCount)
{
switch (button)
{
case APP_OPE_PAUSE_REPLAY: //一時停止/再開
if(bButtonClosed)
{
if(ysPlay == 1)
{
ysPlay = 0;
APP_PlayerCommand(PLAYER_CMD_STOP); //停止
}
else
{
ysPlay = 1;
APP_PlayerCommand(PLAYER_CMD_PLAY); //演奏再開
}
}
break;
case APP_OPE_SKIP: //スキップ
if(bButtonClosed)
{
APP_PlayerCommand ( PLAYER_CMD_NEXT_FILE ); //次のファイル演奏へ
}
break;
default:
break;
}
}
void APP_BtnTask(void) //ボタンスイッチの変化割り込み検出
{
//BUTTON1
if(BtnEvent[0] == 1) //ファイル オープン/クローズ //Btn1変化割り込み発生の場合
{
BtnEvent[0] = 0;
if(PORTBbits.RB0 == 0) //Btn1
{
delay_ms(100); //チャタリング防止
if(PORTBbits.RB0 == 0)
{
LATGbits.LATG15 = 1;
APP_OnButtonEvent(APP_OPE_PAUSE_REPLAY,true,0); //ファイル オープン/クローズ
delay_ms(100);
}
}
}
//BUTTON2
if(BtnEvent[1] == 1) //スキップ //変Btn2化割り込み発生の場合
{
BtnEvent[2] = 0;
if(PORTBbits.RB1 == 0) //Btn2
{
delay_ms(100); //チャタリング防止
if(PORTBbits.RB1 == 0)
{
APP_OnButtonEvent(APP_OPE_SKIP,true,0); //スキップ
delay_ms(100);
}
}
}
}
// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************
// *****************************************************************************
/* Application Data
Summary:
Holds application data
Description:
This structure holds the application's data.
Remarks:
This structure should be initialized by the APP_Initialize function.
Application strings and buffers are be defined outside this structure.
*/
APP_DATA appData;
// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************
/* TODO: Add any necessary callback functions.
*/
// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************
/* TODO: Add any necessary local functions.
*/
// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************
/*******************************************************************************
Function:
void APP_Initialize ( void )
Remarks:
See prototype in app.h.
*/
void APP_Initialize ( void )
{
/* Place the App state machine in its initial state. */
appData.state = APP_STATE_INIT;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_clear();
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"USB Root_Dir ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," File Search "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(2000);
DiskState = DISK_STATE_REMOVED;
//文字列送信
WriteString("UART Connected !!\r\n");
}
/******************************************************************************
Function:
void APP_Tasks ( void )
Remarks:
See prototype in app.h.
*/
void APP_Tasks ( void )
{
/* Check the application's current state. */
switch ( appData.state )
{
/* Application's initial state. */
case APP_STATE_INIT:
{
bool appInitialized = true;
if (appInitialized)
{
appData.state = APP_STATE_SERVICE_TASKS;
}
break;
}
case APP_STATE_SERVICE_TASKS:
{
DISK_Tasks(); //USBディスク 初期化、読み出し
APP_BtnTask(); //ボタンスイッチの変化割り込み検出
break;
}
/* TODO: implement your application state machine.*/
/* The default state should never be executed. */
default:
{
/* TODO: Handle error in application's state machine. */
break;
}
}
}
/*******************************************************************************
End of File
*/