BouKiCHi Tokonabegawa / Mbed 2 deprecated nlgplay_130

Dependencies:   SDFileSystemEx mbed

Files at this revision

API Documentation at this revision

Comitter:
bkc_mbed
Date:
Mon Feb 08 05:49:26 2016 +0000
Child:
1:29f0e76a9999
Commit message:
ver 1.22

Changed in this revision

SDFileSystemEx.lib Show annotated file Show diff for this revision Revisions of this file
lcd.cpp Show annotated file Show diff for this revision Revisions of this file
lcd.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nlg_mini.cpp Show annotated file Show diff for this revision Revisions of this file
nlg_mini.h Show annotated file Show diff for this revision Revisions of this file
pindef.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystemEx.lib	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/bkc_mbed/code/SDFileSystemEx/#3701e9942a16
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcd.cpp	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * lcd.cpp : AQM0802A mini library
+ *
+ *  Based on LCD module "AQM0802A-RN-GBW" sample program
+ *  Copyright (c) 2013 Yoshihiro TSUBOI
+ *
+ *  Original Arduino version was developed by
+ *  Copyright (c) 2013 Masahiro WAKAYAMA at SWITCH SCIENCE
+ *
+ *  Released under the MIT License: http://mbed.org/license/mit
+ *
+ */
+
+#include "mbed.h"
+
+#include "lcd.h"
+#include "pindef.h"
+
+LCD::LCD()
+{
+  i2c = new I2C(DP_SDA, DP_SCL); // sda, scl
+}
+
+#define LCD_ADDR 0x7C
+
+void LCD::cmd(char x)
+{
+  char data[2];
+  data[0] = 0x00; // CO = 0,RS = 0
+  data[1] = x;
+  i2c->write(LCD_ADDR, data, 2);
+}
+
+void LCD::contdata(char x)
+{
+  char data[2];
+  data[0] = 0xC0; //0b11000000 CO = 1, RS = 1
+  data[1] = x;
+  i2c->write(LCD_ADDR, data, 2);
+}
+
+void LCD::lastdata(char x)
+{
+  char data[2];
+  data[0] = 0x40; //0b11000000 CO = 0, RS = 1
+  data[1] = x;
+  i2c->write(LCD_ADDR, data, 2);
+}
+
+
+void LCD::setContrast(unsigned char c) {
+  cmd(0x39);
+  cmd(0x70 | (c & 0x0f)); // contrast Low
+  cmd(0x5C | ((c >> 4) & 0x03)); // contast High/icon/power
+  cmd(0x38);
+}
+
+void LCD::init() {
+  int cont = 0;
+  wait(0.04);
+  // LCD initialize
+  cmd(0x38); // function set
+  cmd(0x39); // function set
+  cmd(0x04); // EntryModeSet
+  cmd(0x14); // interval osc
+  cmd(0x70 | (cont & 0xF)); // contrast Low
+  cmd(0x5C | ((cont >> 4) & 0x3)); // contast High/icon/power
+  cmd(0x6C); // follower control
+  wait(0.2);
+  cmd(0x38); // function set
+  cmd(0x0C); // Display On
+  cmd(0x01); // Clear Display
+  wait(0.2); // need additional wait to Clear Display
+
+  setContrast(36);
+}
+
+
+// 文字と空白で1行を埋める
+void LCD::printStrFill(const char *s)
+{
+  int idx = 0;
+  for(idx = 0; idx < 8; idx++)
+  {
+    if(idx < 7) {
+      contdata(*s);
+    } else {
+      lastdata(*s);
+    }
+    if (*s) s++;
+  }
+}
+
+void LCD::printStr(const char *s)
+{
+  int idx = 0;
+  while(*s && idx < 8) {
+    if(*(s + 1)) {
+      contdata(*s);
+    } else {
+      lastdata(*s);
+    }
+    s++;
+    idx++;
+  }
+}
+
+void LCD::setCursor(unsigned char x,unsigned char y)
+{
+  cmd(0x80 | (y * 0x40 + x));
+}
+
+void LCD::printStrY(int y,const char *s)
+{
+  setCursor(0, y);
+  printStrFill(s);
+}
+
+void LCD::printStrYscr(int y,const char *s)
+{
+  int cnt = strlen(s) - 7;
+  if (cnt <= 0)
+    cnt = 1;
+
+  for(int i = 0; i < cnt; i++)
+  {
+    setCursor(0, y);
+    printStr(s + i);
+    wait(0.5);
+  }
+}
+
+
+void LCD::printStr2(const char *s, const char *s2)
+{
+  setCursor(0,0);
+  printStrFill(s);
+  setCursor(0,1);
+  printStrFill(s2);
+}
+
+void LCD::cls(void)
+{
+    setCursor(0, 0);
+    printStrFill("");
+    setCursor(0, 1);
+    printStrFill("");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcd.h	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,27 @@
+#ifndef __LCD_H__
+#define __LCD_H__
+
+#include "mbed.h"
+
+class LCD {
+public:
+    LCD();
+
+    void printStr(const char *s);
+    void setContrast(unsigned char c);
+    void setCursor(unsigned char x,unsigned char y);
+    void cls(void);
+    void init(void);
+    void printStr2(const char *s, const char *s2);
+    void printStrY(int y,const char *s);
+    void printStrYscr(int y,const char *s);
+
+protected:
+    void cmd(char x);
+    void contdata(char x);
+    void lastdata(char x);
+    void printStrFill(const char *s);
+    I2C *i2c;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,1419 @@
+//
+// NLGPLAY : NLG file player for mbed
+//
+// example to write :
+// ./lpc21isp -bin file.bin /dev/cu.usbserial-??? 115200 12000
+//
+// 20151008: updated.
+//
+
+#include <stdio.h>
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "lcd.h"
+
+#include "nlg_mini.h"
+
+// SPIモード
+// #define USE_SPI
+
+#ifdef TARGET_LPC1114
+// 高速I/Oモード(LPC1114専用)
+#define USE_FASTIO
+#endif
+
+// ピンアサイン切り替え
+#include "pindef.h"
+
+
+#define PRG_NAME "NLGPLAY"
+#define PRG_VER_BASE "V1.22"
+
+#ifndef USE_SPI
+#define PRG_VER PRG_VER_BASE
+#else
+#define PRG_VER PRG_VER_BASE "S"
+#endif
+
+
+//#pragma O3
+//#pragma Otime
+
+
+
+// (pinname, mode)
+DigitalIn sw_play(DP_PLAY, PullUp);
+DigitalIn sw_next(DP_NEXT, PullUp);
+DigitalIn sw_prev(DP_PREV, PullUp);
+
+#define MAX_PATH 128
+#define MAX_FILENAME 64
+#define MAX_DIR 64
+
+// Global Variable
+struct
+{
+  bool stop;
+  bool prev;
+  bool one_mode;
+
+  int idx;
+  int max_entries;
+
+  char playlist[MAX_FILENAME];
+  char file[MAX_FILENAME];
+  char cwd[MAX_DIR];
+
+  NLG_CTX nlg;
+  int total_sec;
+} g;
+
+// キーコード
+#define SW_PLAY 1
+#define SW_NEXT 2
+#define SW_PREV 4
+
+
+// ボタンが離されるのを待つ
+void wait_key_up(void)
+{
+    while(!sw_next || !sw_play || !sw_prev);
+}
+
+// ボタンの入力を待つ
+void wait_key_down(void)
+{
+    while(sw_next && sw_play && sw_prev);
+}
+
+// キー入力
+int get_key(void)
+{
+  int key = 0;
+  
+  if (!sw_next)
+    key |= SW_NEXT;
+  if (!sw_play)
+    key |= SW_PLAY;
+  if (!sw_prev)
+    key |= SW_PREV;
+  return key;
+}
+
+// キー開放待ち
+void wait_relkey(void)
+{
+  wait_key_up();
+  wait(0.1);
+}
+
+// キー待ち
+int wait_anykey(void)
+{
+    wait_key_down();
+    int key = get_key();
+
+    wait(0.1);
+    wait_relkey();
+
+    return key;
+}
+
+// LED
+DigitalOut led1(LED1, 0);
+DigitalOut led2(LED2, 0);
+
+// SPI: MOSI, MISO, SCLK, CS
+SDFileSystem sd(DP_MOSI, DP_MISO, DP_SCLK, DP_SCS, "sd");
+
+// LCD
+LCD lcd;
+
+#define _WAIT for(int wcnt=0; wcnt < 2; wcnt++)
+
+
+////////////////
+// 高速IO
+
+#define DBS IO_01 // DATA
+#define CTS IO_02 // CTRL
+#define RCK IO_04 // LATCH
+#define SCK IO_03 // SCLK
+
+
+DigitalOut io01(DP_IO01, 0); // P1_4
+DigitalOut io02(DP_IO02, 0); // P0_3
+DigitalOut io03(DP_IO03, 0); // P1_8
+DigitalOut io04(DP_IO04, 0); // P0_11
+
+#if 0
+// NBV3での試し機能
+#define IO_A0 io05
+#define IO_WR io06
+
+DigitalOut io05(DP_IO05, 0); // P1_9
+DigitalOut io06(DP_IO06, 0); // P1_2
+
+#endif
+
+#define IO_01 (1 << 4)  // DBS P1_4
+#define IO_02 (1 << 3)  // CTS P0_3
+#define IO_03 (1 << 8)  // SCK P1_8
+#define IO_04 (1 << 11) // RCK P0_11
+
+#ifdef USE_FASTIO
+
+// ポート出力
+#define DATA_HI LPC_GPIO1->DATA |= DBS
+#define DATA_LO LPC_GPIO1->DATA &= ~DBS
+#define CTRL_HI LPC_GPIO0->DATA |= CTS
+#define CTRL_LO LPC_GPIO0->DATA &= ~CTS
+#define SCK_HI LPC_GPIO1->DATA |= SCK
+#define SCK_LO LPC_GPIO1->DATA &= ~SCK
+#define RCK_HI LPC_GPIO0->DATA |= RCK
+#define RCK_LO LPC_GPIO0->DATA &= ~RCK
+
+// 出力設定
+#define PORT_DIR  LPC_GPIO0->DIR |= (IO_02 | IO_04); \
+ LPC_GPIO1->DIR |= (IO_01 | IO_03)
+
+#else
+
+// ポート出力
+#define DATA_HI io01 = 1
+#define DATA_LO io01 = 0
+#define CTRL_HI io02 = 1
+#define CTRL_LO io02 = 0
+#define SCK_HI io03 = 1
+#define SCK_LO io03 = 0
+#define RCK_HI io04 = 1
+#define RCK_LO io04 = 0
+
+// 出力設定
+#define PORT_DIR 
+
+#endif
+
+SPI *spi;
+
+// I/O初期化
+void ioInit()
+{
+  // SPIインスタンスの取得
+  spi = sd.getSPI();
+  // 出力
+  PORT_DIR;
+}
+
+
+#ifndef USE_SPI
+// 8x2ビットモード
+
+#define SHIFTOUT io8x2Out
+
+// 8bit 出力
+void byteOut(unsigned char data)
+{
+    int i;
+
+    for(i = 0; i < 8; i++)
+    {
+        if (data & 0x80)
+            DATA_HI;
+        else
+            DATA_LO;
+
+        data <<= 1;
+        
+        SCK_HI;
+        SCK_LO;
+    }
+}
+
+// 8x2ビット出力 or 16bit出力選択可能
+void io8x2Out(unsigned int ctrl, unsigned int data)
+{
+    int i;
+    // シフトレジスタ直列モード
+    if (g.one_mode)
+    {
+        // データ順
+        // <- CCCCCCCC76543210
+        
+        byteOut(ctrl);
+        byteOut(data);
+                
+        // ラッチ
+        RCK_HI;
+        RCK_LO;
+    }
+    else 
+    {
+    // シフトレジスタ並列モード
+        for(i = 0; i < 8; i++)
+        {
+            /* 2ビット分のデータをそれぞれ出力 */
+            if (ctrl & 0x80)
+                CTRL_HI;
+            else
+                CTRL_LO;
+    
+            if (data & 0x80)
+                DATA_HI;
+            else
+                DATA_LO;
+    
+            ctrl <<= 1;
+            data <<= 1;
+            // シフトクロック
+            SCK_HI;
+            SCK_LO;
+        }
+    
+        // ラッチ
+        RCK_HI;
+        RCK_LO;
+    }
+}
+
+#else
+
+// 16bitモード
+#define SHIFTOUT io16Out
+
+
+
+// 16bit 出力
+void io16Out(unsigned char ctrl, unsigned char data)
+{
+    spi->write(ctrl);
+    spi->write(data);
+
+    // byteOut(ctrl);
+    // byteOut(data);
+
+    // LATCH
+    RCK_HI;
+    RCK_LO;
+}
+
+#endif
+
+/* 制御信号定義 */
+#define CS_FM3 (1 << 0)
+#define CS_PSG (1 << 1)
+#define CS_FM1 (1 << 2)
+#define CS_FM2 (1 << 3)
+#define A0     (1 << 4)
+#define WR     (1 << 5)
+#define ICL    (1 << 6)
+#define CTL    (1 << 7)
+
+
+/* アクティブローの制御信号 */
+#define ACTLOW (CS_PSG | CS_FM1 | CS_FM2 | CS_FM3 | WR | ICL)
+
+
+/* NBV2互換出力 */
+void regOutBase(int addr, int data, int select)
+{
+    /* アドレスを出力 */
+    /* A0をローにして待つ */
+    int ctrl = ACTLOW;
+    
+    /* 裏レジスタ */
+    if (addr >= 0x100)
+        ctrl |= CTL;
+    addr &= 0xff;
+  
+    SHIFTOUT(ctrl, 0x00);
+    SHIFTOUT(ctrl & ~(select | WR), addr);
+    SHIFTOUT(ctrl, addr);
+
+    /* チップ処理待ち */
+
+    /* データを出力 */
+    /* A0をハイにして待つ */
+    ctrl |= A0;
+    SHIFTOUT(ctrl, 0x00);
+    SHIFTOUT(ctrl & ~(select | WR), data);
+    SHIFTOUT(ctrl, data);
+
+    /* チップ処理待ち */
+}
+
+/* 出力 */
+#define regPSGOut(addr, data) regOutBase(addr, data, CS_PSG)
+#define regFMOut(addr, data) regOutBase(addr, data, CS_FM1)
+#define regFM2Out(addr, data) regOutBase(addr, data, CS_FM2)
+
+/* 音源出力 */
+#define WritePSG regPSGOut
+#define WriteOPM regFMOut
+#define WriteOPM2 regFM2Out
+
+
+/* ミュート */
+void boardMute(void)
+{
+    int i;
+
+    /* PSG初期化 */
+    regPSGOut(0x00,0);
+    regPSGOut(0x01,0);
+
+    regPSGOut(0x06, 0x00);
+    regPSGOut(0x07, 0x3f); // ALL OFF
+    regPSGOut(0x08, 0x00); // CH.A 0
+    regPSGOut(0x09, 0x00); // CH.B 0
+    regPSGOut(0x0a, 0x00); // CH.C 0
+
+    /* MUTE(disable) */
+    for(i = 0x20; i < 0x28; i++)
+    {
+        regFMOut(i, 0x00);
+        regFM2Out(i, 0x00);
+    }
+
+    // KEYOFF
+    for(i = 0x00; i < 0x08; i++)
+    {
+        regFMOut(0x08, i & 0x07);
+        regFM2Out(0x08, i & 0x07);
+    }
+
+    // FORCE RELEASE
+    for(i= 0x00; i < 0x20; i++)
+    {
+        regFMOut(0xE0 + i, 0x0f);
+        regFM2Out(0xE0 + i, 0x0f);
+    }
+
+    // OPLL ミュート
+    for(i= 0x00; i <= 0x08; i++)
+    {
+        regFMOut(0x20 + i, 0x00);
+        regFMOut(0x30 + i, 0x0f);
+        regFM2Out(0x20 + i, 0x00);
+        regFM2Out(0x30 + i, 0x0f);
+    }
+
+}
+
+/* ボード初期化 */
+void boardInit(void)
+{
+    wait_ms(20);
+    /* ICLのみをLOW(アクティブ)にする */
+    SHIFTOUT(ACTLOW & ~(ICL), 0);
+    wait_ms(150);
+
+    /* 元に戻す */
+    SHIFTOUT(ACTLOW, 0);
+    wait_ms(10);
+}
+
+//////////////////////////////////////////
+
+// 表示
+void dispTime()
+{
+    char buf[16];
+    sprintf(buf, "%02d:%02d",
+        g.total_sec / 60,
+        g.total_sec % 60);
+
+    lcd.setCursor(3,1);
+    lcd.printStr(buf);
+}
+
+#define WAIT_US 10000 // 10ms
+#define SEC_US 1000000 // 1sec
+#define NEXT_MAX_US 300000 // 300ms
+
+/* NLGの再生 */
+int PlayNLG_Loop(void)
+{
+    int cmd;
+    int addr, data;
+
+    int result = 0;
+
+    int us = 0;
+    int diff_us = 0;
+
+    int count_us = 0;
+    int total_us = 0;
+
+    // NEXTボタンのカウンタ
+    int next_count = 0;
+
+    bool wait_skip = false;
+
+
+    // GetTickUsNLG
+    int tick_us = GetTickUsNLG(&g.nlg);
+
+    // printf("tick_us:%d\n", tick_us);
+
+    g.total_sec = 0;
+
+    // タイマースタート
+    Timer t;
+    t.start();
+
+    // 表示
+    dispTime();
+
+    // LED消灯
+    led1 = 0;
+    led2 = 0;
+
+    // LEDカウンタ
+    int led_cnt1 = 0;
+    int led_cnt2 = 0;
+
+    // ループ
+    while(!g.stop)
+    {
+        /* ウエイトの処理 */
+        while (count_us >= WAIT_US)
+        {
+            // ボタンチェック
+            if (!sw_next)
+            {
+                // NEXTが押されている
+                if (next_count < NEXT_MAX_US)
+                    next_count += count_us;
+                else
+                {
+                    // 早送り
+                    next_count = NEXT_MAX_US;
+                    wait_skip = true;
+                }
+            }
+            else
+            {
+                // NEXTが離されている
+                wait_skip = false;
+
+                // 一瞬だけボタンが押された場合、次の曲へ
+                if (next_count > 0 && next_count < NEXT_MAX_US)
+                {
+                    next_count = 0;
+                    goto song_end;
+                }
+
+                // 早送りの終了
+                if (next_count == NEXT_MAX_US)
+                {
+                    next_count = 0;
+                }
+            }
+            // PREVが押された
+            if (!sw_prev)
+            {
+                g.prev = true;
+                goto song_end;
+            }
+
+            // PLAYが押された
+            if (!sw_play)
+            {
+                g.stop = true;
+                goto song_end;
+            }
+
+            // スキップでなければ次のタイミングまで待つ
+            while(!wait_skip && (us = t.read_us()) + diff_us < count_us);
+
+            // タイマーリセット
+            if (!wait_skip)
+                t.reset();
+
+            // 差分を計算
+            diff_us += us;
+            while(diff_us >= count_us)
+              diff_us -= count_us;
+
+            // 積算する
+            total_us += count_us;
+            count_us = 0;
+
+            // 1秒で積算カウントをリセットする
+            if (total_us >= SEC_US)
+            {
+                while(total_us >= SEC_US)
+                {
+                    g.total_sec++;
+                    total_us -= SEC_US;
+                }
+                // 表示
+                dispTime();
+            }
+        }
+
+        /* コマンドの読み出し */
+        cmd = ReadNLG(&g.nlg);
+        if (cmd == EOF)
+        {
+            result = EOF;
+            break;
+        }
+        
+        if (cmd < 0x80)
+        {
+            addr = ReadNLG(&g.nlg);
+            data = ReadNLG(&g.nlg);
+            
+            // 裏レジスタ
+            if (cmd >= 0x40)
+                addr |= 0x100;
+            
+            switch(cmd & 0x3f)
+            {
+            case CMD_PSG:
+                WritePSG(addr, data);
+                break;
+            case CMD_FM1:
+                WriteOPM(addr, data);
+                break;
+            case CMD_FM2:
+                WriteOPM2(addr, data);
+                break;
+            }
+        }
+        else
+        {
+            /* コマンドの処理 */
+            switch (cmd)
+            {
+                case CMD_IRQ:
+                    count_us += tick_us;
+        
+                    // LED1
+                    led_cnt1++;
+                    if (led_cnt1 >= 48)
+                    {
+                        led_cnt1 = 0;
+                        led1 = !led1;
+                    }
+
+                    // LED2
+                    led_cnt2++;
+                    if (led_cnt2 >= 192)
+                    {
+                        led_cnt2 = 0;
+                        led2 = !led2;
+                    }
+                break;
+                case CMD_CTC0:
+                    data = ReadNLG(&g.nlg);
+                    SetCTC0_NLG(&g.nlg, data);
+                    tick_us = GetTickUsNLG(&g.nlg);
+                    // printf("CTC0:%d tick_us:%d\n", data, tick_us);
+        
+                break;
+                case CMD_CTC3:
+                    data = ReadNLG(&g.nlg);
+                    SetCTC3_NLG(&g.nlg, data);
+                    tick_us = GetTickUsNLG(&g.nlg);
+                    // printf("CTC3:%d tick_us:%d\n", data, tick_us);
+                break;
+            }
+        }
+    }
+
+song_end:
+
+    return result;
+}
+
+
+// ファイルを再生する
+int play_file(const char *filename)
+{
+    /* NLGファイルを開く */
+    if (OpenNLG(&g.nlg, filename) < 0)
+    {
+        return -1;
+    }
+
+    /* 再生する */
+    PlayNLG_Loop();
+
+    /* NLGファイルを閉じる */
+    CloseNLG(&g.nlg);
+
+    return 0;
+}
+
+// error_sdcard()
+// エラー!
+void error_sdcard(void)
+{
+    lcd.printStr2("SD CARD", "ERROR!");
+
+    while(1);
+}
+
+// COM mode
+void loop_for_com(void)
+{
+    int sw, val;
+    int adr = 0x00;
+    int baud = 9600;
+    char buf[16];
+    Serial pc(DP_TX, DP_RX);
+
+    lcd.cls();
+    lcd.printStrY(0, "COM MODE");
+
+    sprintf(buf, "%-8d", baud);
+    lcd.printStrY(1, buf);
+
+    pc.printf("COM\n");
+
+    // タイマースタート
+    Timer t;
+    t.start();
+
+    while(1)
+    {
+
+        sw = pc.getc();
+
+        // 0は同期リセット
+        if (sw == 0x00)
+            continue;
+
+        if (sw >= 1 && sw <= 3)
+        {
+          adr = pc.getc();
+          val = pc.getc();
+        }
+
+        switch(sw)
+        {
+            case 1:
+                regFMOut(adr, val);
+            break;
+            case 2:
+                regFM2Out(adr, val);
+            break;
+            case 3:
+                regPSGOut(adr, val);
+            break;
+            case 0x0f:
+                // 通信速度設定
+                val = pc.getc();
+                baud = (9600 * val);
+                sprintf(buf, "%-8d", baud);
+                lcd.printStrY(1, buf);
+
+                pc.baud(baud);
+            break;
+            case 0x10:
+                //
+                val = pc.getc();
+                val = (val * 10000);
+                while(t.read_us() < val);
+                pc.putc('.');
+                t.reset();
+            break;
+            case 0x11:
+                t.reset();
+            break;
+        }
+
+        // pc.printf("sw = %02x, adr = %02x, val = %02x\n", sw, adr, val);
+    }
+}
+
+
+// chk_isdir
+// ディレクトリか否か
+// return : bool
+// false if not directory
+
+bool chk_isdir(const char *cwd, const char *dir)
+{
+    char tmp[256];
+    sprintf(tmp,"%s/%s", cwd, dir);
+
+    DIR *dp = opendir(tmp);
+    if (!dp)
+      return false;
+
+    closedir(dp);
+    return true;
+}
+
+#define EXT_LIST ".lst"
+#define EXT_NLG ".nlg"
+
+// get_fileentry
+// index : index of list , -1 = return number of entries
+// is_mode : 0 = normal mode
+// mode = MODE_GETDIR | MODE_GETLIST | MODE_FILE
+// return : int
+// -1 = not found or error
+
+#define MODE_FILE 0
+#define MODE_GETDIR 1
+#define MODE_GETLIST 2
+
+int get_fileentry(int index, int mode)
+{
+    // return -1 if entry is zero.
+    int count = 0;
+    DIR *dp = opendir(g.cwd);
+
+    g.file[0] = 0;
+
+    if (!dp)
+        return -1;
+
+    struct dirent *dent = NULL;
+
+    while(1)
+    {
+        // エントリの読み出し
+        dent = readdir(dp);
+
+        // 失敗
+        if (!dent)
+            break;
+
+        // リソースか隠しファイル
+        if (dent->d_name[0] == '.')
+            continue;
+
+        // 拡張子の取得
+        char *ext = strrchr(dent->d_name, '.');
+
+        switch(mode)
+        {
+          // ディレクトリモード
+          case MODE_GETDIR:
+            // ディレクトリでなければ継続
+            if (!chk_isdir(g.cwd, dent->d_name))
+                continue;
+          break;
+
+          // プレイリストモード
+          case MODE_GETLIST:
+            // リストでなければ無視
+            if (!ext || strcasecmp(ext, EXT_LIST) != 0)
+              continue;
+          break;
+
+          // ファイルモード
+          case MODE_FILE:
+            // NLGファイルでなければ継続
+            if (!ext || strcasecmp(ext, EXT_NLG) != 0)
+                continue;
+          break;
+        }
+
+        // カウントアップ
+        count++;
+
+        // カウントモードかカウントがindex未満で継続
+        if (index < 0 || count <= index)
+            continue;
+
+        // ファイル名をコピーして終了
+        strcpy(g.file, dent->d_name);
+        break;
+
+    }
+    closedir(dp);
+    return count;
+}
+
+
+//
+// タイトル表示
+//
+int putTitle()
+{
+    int count_ms = 0;
+    int diff_us = 0;
+    int us = 0;
+    int key = get_key();
+
+    // キー入力時はキャンセル
+    if (key)
+      return key;
+
+    lcd.printStr2(PRG_NAME, PRG_VER);
+    Timer t;
+    t.start();
+
+    // 1500msまでループする
+    while(count_ms < 1500)
+    {
+      while((us = t.read_us()) + diff_us < 1000);
+      t.reset();
+
+      // キー入力があれば終了
+      key = get_key();
+      if (key)
+        return key;
+
+      // 差分を現在の時間に足して次の差分を作る
+      diff_us += us;
+
+      while(diff_us >= 1000)
+      {
+        count_ms++;
+        diff_us -= 1000;
+      }
+    }
+
+    return 0;
+}
+
+// 情報の表示
+void show_info(int files)
+{
+    char buf[16];
+
+    Timer t;
+    int result_us = 0;
+    t.reset();
+    t.start();
+
+    // 実際の書き込み時間を計測する
+    regFMOut(0x20, 0x00);
+    regFMOut(0x20, 0x00);
+    regFMOut(0x20, 0x00);
+    regFMOut(0x20, 0x00);
+    regFMOut(0x20, 0x00);
+
+    // 経過時間を得る
+    result_us = t.read_us();
+    t.stop();
+
+    // 平均値
+    result_us /= 5;
+
+    // 結果表示
+    printf("result_us=%dus\n", result_us);
+    sprintf(buf, "R:%dus", result_us);
+    lcd.printStrY(1, buf);
+    wait(3);
+
+    // コンパイル時の日付
+    sprintf(buf, "%8s", __DATE__);
+    lcd.printStrYscr(1, buf);
+    wait(3);
+
+    if (files < 0)
+        lcd.printStrY(1, "NO FILES");
+    else
+    {
+        sprintf(buf, "%3dfiles", files);
+        lcd.printStrY(1, buf);
+    }
+    wait(3);
+    lcd.cls();
+}
+
+// ビットテスト
+
+void bit_test()
+{
+    char buf[9];
+    lcd.printStrY(0, "BIT_TEST");
+
+    wait_key_up();
+
+    int pin = 0;
+    int mode = 0;
+    char sig;
+
+    while(1)
+    {
+        // 表示
+        if (mode & 1)
+          sig = 'C'; // コントロール
+        else
+          sig = 'D'; // データ
+
+        if (mode & 2)
+          strcpy(buf,"00");
+        else
+          sprintf(buf, "%c%d", sig, pin);
+
+        lcd.printStrY(1, buf);
+
+        // 出力
+        if (mode & 2)
+        {
+            SHIFTOUT(0xff, 0x00);
+        }
+        else
+        {
+            int bit = (1 << pin);
+            if (mode & 1)
+              SHIFTOUT(0xff & ~(bit), 0); // コントロール
+            else
+              SHIFTOUT(0xff, bit); // データ
+        }
+
+        // キー待ち
+        int key = wait_anykey();
+
+        // 再生
+        if (key & SW_PLAY)
+        {
+          mode ^= 2;
+          continue;
+        }
+        // 次
+        if (key & SW_NEXT)
+        {
+          pin++;
+          if (pin > 7)
+          {
+              pin = 0;
+              mode = (mode + 1) & 1;
+          }
+        }
+        // 前
+        if (key & SW_PREV)
+        {
+          pin--;
+          if (pin < 0)
+          {
+              pin = 7;
+              mode = (mode - 1) & 1;
+          }
+        }
+    }
+}
+
+//
+// ファイル選択表示
+void disp_filesel(int mode)
+{
+  char buf[16];
+
+  char *mode_name;
+  switch(mode)
+  {
+    case MODE_GETLIST:
+      mode_name = "LIST SEL";
+    break;
+    case MODE_GETDIR:
+      mode_name = "DIR  SEL";
+    break;
+    default:
+      mode_name = "FILE SEL";
+  }
+
+  strncpy(buf, g.file, 8);
+  buf[8] = 0;
+
+  // 表示
+  lcd.printStr2(buf, mode_name);
+}
+
+//
+// ファイル/ディレクトリ選択
+// mode = MODE_GETLIST | MODE_GETDIR | MODE_FILE
+//
+int file_select(int mode)
+{
+    // ファイル数を得る
+    int files = get_fileentry(-1, mode);
+
+    // 最大エントリー
+    g.max_entries = files - 1;
+
+    // ファイル名の取得
+    get_fileentry(g.idx, mode);
+
+    // 表示
+    disp_filesel(mode);
+
+    // リリース待ち
+    wait_relkey();
+
+    while(1)
+    {
+        // ファイル名の取得
+        get_fileentry(g.idx, mode);
+
+        // 表示
+        disp_filesel(mode);
+
+        // キー待ち
+        int key = wait_anykey();
+
+        // 次のエントリ
+        if (key & SW_NEXT)
+        {
+            if (g.idx < g.max_entries)
+                g.idx++;
+            else
+                g.idx = 0;
+        }
+
+        // 前のエントリ
+        if (key & SW_PREV)
+        {
+            if (g.idx > 0)
+                g.idx--;
+            else
+                g.idx = g.max_entries;
+        }
+        // 再生ボタンを押した
+        if (key & SW_PLAY)
+            break;
+    }
+
+    return g.idx;
+}
+
+// get_playlist()
+// index = リスト位置, -1でエントリ数を返す
+int get_playlist(int index)
+{
+    int count = 0;
+    FILE *fp = fopen(g.playlist, "r");
+
+    g.file[0] = 0;
+
+    // プレイリストが開けない
+    if (!fp)
+        return -1;
+
+    while(1)
+    {
+        // プレイリストから一行読み込む
+        char *p = fgets(g.file, MAX_FILENAME, fp);
+
+        // EOFなので終了
+        if (!p)
+            break;
+
+        // サイズ
+        int len = strlen(g.file);
+
+        // CR/LFをトリムする
+        while(len > 0 && (unsigned char)g.file[len - 1] < 0x20)
+        {
+            g.file[len - 1] = 0x00;
+            len--;
+        }
+
+        // 空行は飛ばす
+        if (!len)
+            continue;
+
+        count++;
+
+        // カウントモードかカウントがindex未満で継続
+        if (index < 0 || count <= index)
+            continue;
+        else
+            break;
+    }
+
+    // プレイリストを閉じる
+    fclose(fp);
+
+#if defined(__MICROLIB) && defined(__ARMCC_VERSION)
+    free(fp);
+#endif
+
+    return count;
+}
+
+
+// グローバル変数初期化
+void init_globe(void)
+{
+  memset(&g, 0, sizeof(g));
+  strcpy(g.cwd,"/sd");
+}
+
+// パスの作成
+void make_path(char *path, const char *dir, const char *file)
+{
+  sprintf(path, "%s/%s", dir, file);
+}
+
+// 再生モード
+void play_mode(void)
+{
+  int files = -1;
+
+  // プレイリストモードか否か
+  if (g.playlist[0])
+      files = get_playlist(-1);
+  else
+      files = get_fileentry(-1, MODE_FILE);
+
+  // エラー表示
+  if (files < 0)
+      error_sdcard();
+
+  g.max_entries = files - 1;
+
+  bool repeat_flag = false;
+
+  // ファイルが無い
+  if (files < 1)
+  {
+      lcd.cls();
+      lcd.printStrY(0, "NO FILES");
+      wait(1);
+  }
+
+  // 再生モードループ
+  while(1)
+  {
+      char path[MAX_PATH];
+      char buf[16];
+
+      // プレイリストかどうか?
+      if (g.playlist[0])
+          get_playlist(g.idx);
+      else
+          get_fileentry(g.idx, MODE_FILE);
+
+      // フルパスを作成
+      make_path(path, g.cwd, g.file);
+
+      // 曲番号
+      sprintf(buf, "%2d ", g.idx + 1);
+
+      // ファイル名名表示
+      lcd.cls();
+      lcd.printStrY(0, g.file);
+      lcd.printStrY(1, buf);
+
+      // 再生開始
+      play_file(path);
+
+      // ミュート
+      boardMute();
+
+      // キー開放待ち
+      wait_relkey();
+
+
+      // 再生ボタンが押された
+      if (g.stop)
+      {
+          // ストップ表示
+          lcd.printStrY(1, "  STOP  ");
+
+          g.stop = false;
+          g.prev = false;
+          g.total_sec = 0;
+
+          // ボード初期化
+          boardInit();
+
+          // ファイル選択
+          file_select(MODE_FILE);
+          continue;
+      }
+
+      // 前の曲を再生
+      if (g.prev)
+      {
+          g.prev = false;
+
+          // 同じ曲を再生
+          if (g.total_sec >= 2)
+            continue;
+
+          if (g.idx > 0)
+              g.idx--;
+          else
+              g.idx = g.max_entries;
+
+          continue;
+      }
+
+      // 繰り返しではない
+      if (!repeat_flag)
+      {
+          if (g.idx < g.max_entries)
+              g.idx++;
+          else
+              g.idx = 0;
+      }
+      repeat_flag = false;
+  }
+}
+
+
+
+//
+// メニュー選択
+//
+#define MENU_FILE 0
+#define MENU_DIR 1
+#define MENU_LIST 2
+#define MENU_INFO 3
+#define MENU_COM 4
+#define MENU_TEST 5
+#define MENU_SMODE 6
+#define MENU_MAX 6
+
+// メニュー文字列
+const char *menu_modes[] =
+{
+  "FILE", // 0
+  "DIR",  // 1
+  "LIST", // 2
+  "INFO", // 3
+  "COM",  // 4
+  "TEST", // 5
+  "Sx16", // 6
+};
+
+// メニュー選択表示
+void menu_disp(int sel)
+{
+  char buf[16];
+
+  // 表示
+  lcd.printStrY(0, "MENU SEL");
+  sprintf(buf, "%02d %-4s", sel, menu_modes[sel]);
+  lcd.printStrY(1, buf);
+}
+
+// モード選択
+int menu_select()
+{
+    int count = 0;
+
+    // 初期表示
+    menu_disp(0);
+
+    // リリース待ち
+    wait_key_up();
+
+    while(1)
+    {
+        // キー待ち
+        int key = wait_anykey();
+
+        // 次
+        if (key & SW_NEXT)
+        {
+            if (count < MENU_MAX)
+                count++;
+            else
+                count = 0;
+        }
+        // 前
+        if (key & SW_PREV)
+        {
+            if (count > 0)
+                count--;
+            else
+                count = MENU_MAX;
+        }
+        // 再生
+        if (key & SW_PLAY)
+            break;
+
+        // 表示
+        menu_disp(count);
+    }
+
+    return count;
+}
+
+// メニューモード
+void menu_mode(void)
+{
+  int files = 0;
+  char path[MAX_PATH];
+
+  menu_start:
+
+  // ボードの初期化
+  boardInit();
+
+  int sw = menu_select();
+  switch(sw)
+  {
+    // ファイル選択
+    case MENU_FILE:
+      file_select(MODE_FILE);
+    break;
+    // ディレクトリ選択
+    case MENU_DIR:
+        file_select(MODE_GETDIR);
+        // パスを結合し、インデックスを初期化
+        make_path(path, g.cwd, g.file);
+        strcpy(g.cwd, path);
+        g.idx = 0;
+    break;
+    // プレイリスト選択
+    case MENU_LIST:
+        file_select(MODE_GETLIST);
+    break;
+    // 情報モード
+    case MENU_INFO:
+          files = get_fileentry(-1, MODE_FILE);
+          show_info(files);
+          goto menu_start;
+    // 通信モード
+    case MENU_COM:
+      loop_for_com();
+    break;
+    // テストモード
+    case MENU_TEST:
+      bit_test();
+    break;
+    // ストレートモード
+    case MENU_SMODE:
+        g.one_mode = true;
+        lcd.printStr2("","Sx16 ON");
+        wait(0.5);
+        goto menu_start;
+    }
+}
+
+//
+// main
+//
+int main()
+{
+    // 初期化
+    init_globe();
+
+    // I/O初期化
+    ioInit();
+
+    // 立ち上がり待ち
+    wait_ms(20);
+
+    // シフトレジスタの初期化
+    SHIFTOUT(0xFF, 0xFF);
+
+    // LCD初期化
+    lcd.init();
+
+    // タイトル表示
+    int key = putTitle();
+
+    // NEXTボタンでメニュー表示
+    if (key & SW_NEXT)
+      menu_mode();
+
+    // 再生モード
+    play_mode();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/6473597d706e
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nlg_mini.cpp	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,149 @@
+
+//
+// nlg_mini.cpp
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nlg_mini.h"
+
+/* 単位を扱いやすいように */
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long dword;
+
+// 変数読み出し(WORD)
+word ReadWORD(byte *p)
+{
+    return
+        ((word)p[0]) |
+        ((word)p[1])<<8;
+}
+
+// 変数読み出し(DWORD)
+dword ReadDWORD(byte *p)
+{
+    return
+        ((dword)p[0]) |
+        ((dword)p[1])<<8 |
+        ((dword)p[2])<<16 |
+        ((dword)p[3])<<24;
+}
+
+// NLGファイルを開く
+int OpenNLG(NLG_CTX *np, const char *filename)
+{
+    byte hdr[0x60];
+
+    np->fp = fopen(filename, "rb");
+
+    // ファイルが開けない
+    if (!np->fp)
+        return NLG_FILEERR;
+
+    // ヘッダ部分の読み込み
+    fread(hdr, 0x60, 1, np->fp);
+
+    // IDの確認
+    if (memcmp(hdr, "NLG1", 4) != 0)
+    {
+        CloseNLG(np);
+        return NLG_UNK_FORMAT;
+    }
+
+    // バージョン
+    np->version = ReadWORD(hdr + 4);
+
+    // クロック
+    np->baseclk = ReadDWORD(hdr + 72);
+
+    // ティック
+    np->tick = ReadDWORD(hdr + 76);
+    np->tick_us = np->tick / 4;
+
+    // 長さ
+    np->length = ReadDWORD(hdr + 88);
+
+    // 位置
+    fseek(np->fp, 0x60, SEEK_SET);
+
+    // CTC初期化
+    np->ctc0 = np->ctc3 = 0;
+
+    return NLG_OK;
+}
+
+// ファイルを閉じる
+void CloseNLG(NLG_CTX *np)
+{
+    if (!np->fp)
+        return;
+
+    fclose(np->fp);
+
+#if defined(__MICROLIB) && defined(__ARMCC_VERSION) // with microlib and ARM compiler
+    free(np->fp);
+#endif
+
+    np->fp = NULL;
+}
+
+// データの読み出し
+int ReadNLG(NLG_CTX *np)
+{
+    return fgetc(np->fp);
+}
+
+// ファイルポインタの位置を取得
+long TellNLG(NLG_CTX *np)
+{
+    return ftell(np->fp);
+}
+
+// ファイルポインタの位置を設定
+void SeekNLG(NLG_CTX *np, long pos)
+{
+    fseek(np->fp, pos, SEEK_SET);
+}
+
+// ティック(us)の取得
+int GetTickUsNLG(NLG_CTX *np)
+{
+    return np->tick_us;
+}
+
+// Set Tick
+// (CTC0 * 64us) * CTC3
+static inline void SetTickNLG(NLG_CTX *np)
+{
+    np->tick = ((np->ctc0 * 256) * np->ctc3);
+    np->tick_us = np->tick / 4;
+}
+
+// CTC0値の設定
+void SetCTC0_NLG(NLG_CTX *np, int value)
+{
+    np->ctc0 = value;
+    SetTickNLG(np);
+}
+
+// CTC3値の設定
+void SetCTC3_NLG(NLG_CTX *np, int value)
+{
+    np->ctc3 = value;
+    SetTickNLG(np);
+}
+
+// 曲の長さを得る
+int GetLengthNLG(NLG_CTX *np)
+{
+    return np->length;
+}
+
+// ベースクロックを得る
+int GetBaseClkNLG(NLG_CTX *np)
+{
+    return np->baseclk;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nlg_mini.h	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,57 @@
+//
+// nlg_mini.h
+//
+
+#ifndef __NLG_MINI_H__
+#define __NLG_MINI_H__
+
+#define CMD_PSG  0x00
+#define CMD_OPM  0x01
+#define CMD_OPM2 0x02
+#define CMD_FM1  0x01
+#define CMD_FM2  0x02
+
+
+#define CMD_IRQ  0x80
+
+#define CMD_CTC0 0x81
+#define CMD_CTC3 0x82
+
+#define NLG_VER (110)
+#define NLG_BASECLK (4000000)
+
+#define NLG_OK (0)
+#define NLG_FILEERR (-1)
+#define NLG_UNK_FORMAT (-2)
+
+
+/* NLGを処理するための構造体 */
+typedef struct
+{
+  FILE *fp;
+
+  int version;
+
+  int baseclk;
+  int tick;
+  int tick_us;
+
+  int length;
+
+  int ctc0;
+  int ctc3;
+
+} NLG_CTX;
+
+int OpenNLG(NLG_CTX *np, const char *filename);
+void CloseNLG(NLG_CTX *np);
+int ReadNLG(NLG_CTX *np);
+long TellNLG(NLG_CTX *np);
+void SeekNLG(NLG_CTX *np, long pos);
+int GetTickUsNLG(NLG_CTX *np);
+void SetCTC0_NLG(NLG_CTX *np, int value);
+void SetCTC3_NLG(NLG_CTX *np, int value);
+int GetLengthNLG(NLG_CTX *np);
+int GetBaseClkNLG(NLG_CTX *np);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pindef.h	Mon Feb 08 05:49:26 2016 +0000
@@ -0,0 +1,68 @@
+#ifndef __PINDEF_H__
+#define __PINDEF_H__
+
+#ifdef TARGET_LPC1114
+
+// NBCTRLV1 / AYC01
+
+// BUTTON
+#define DP_PLAY dp24
+#define DP_NEXT dp10
+#define DP_PREV dp9
+
+// SPI
+#define DP_MOSI dp2
+#define DP_MISO dp1
+#define DP_SCLK dp6
+#define DP_SCS  dp25
+
+// IO
+#define DP_IO01 dp13 // P1_4
+#define DP_IO02 dp26 // P0_3
+#define DP_IO03 dp17 // P1_8
+#define DP_IO04 dp4 // P0_11
+#define DP_IO05 dp18 // P1_9
+#define DP_IO06 dp11 // P1_2
+
+// I2C
+#define DP_SDA dp5
+#define DP_SCL dp27
+
+// SERIAL
+#define DP_TX USBTX
+#define DP_RX USBRX
+
+#else
+
+////  TG-LPC11U35
+
+// BUTTON
+#define DP_PLAY p20
+#define DP_NEXT p19
+#define DP_PREV p18
+
+// SPI
+#define DP_MOSI p5
+#define DP_MISO p6
+#define DP_SCLK p7
+#define DP_SCS  p8
+
+// IO
+#define DP_IO01 p21
+#define DP_IO02 p23 
+#define DP_IO03 p24 
+#define DP_IO04 p25 
+#define DP_IO05 p26 
+#define DP_IO06 p30 
+
+// I2C
+#define DP_SDA p28
+#define DP_SCL p27
+
+// SERIAL
+#define DP_TX p9
+#define DP_RX p10
+
+#endif
+
+#endif
\ No newline at end of file