オリジナルライドウォッチをつくる 〜ハード編〜

オリジナルライドウォッチ改造記事のラストです。実際に遊べる形に持っていくための、ハード改造編です。必要な具材、プログラムにつきましては、それぞれ前々回前回の記事をご参照くださいませ。

前回は私の万丈ライドウォッチというよりかは、「普通のライドウォッチ」の動きを再現するためのプログラムについて説明しました。今回も同じように「普通のライドウォッチ」を作るための説明をした方が親切だとは思うのですが、申し訳ないことに今の私の手元には万丈ライドウォッチしかありませんので、万丈ライドウォッチの作り方としてご説明します。といっても、普通のライドウォッチとの違いは、ハード的には「普通のLEDを使うかフルカラーLEDを使うか」と、「フォームチェンジを認識させるためのリードスイッチを入れるか入れないか」だけの違いですので、ここで説明する内容はほぼそのまま、普通のライドウォッチを作るときにも使えるハズです。

 

まず、DX版ライドウォッチをバラバラに分解します。分解の際は、バネがどこかに飛んでいってしまわないようご注意ください。特に、リングの回転をロックする部分のバネは飛んでいってしまいやすいので注意です(←やりました)。バネが飛んでいってしまって見つからない場合には、例えばノック式ボールペンに入っているバネなどを短く切って代用するなどしても良いと思います。

上の写真の分解はまだ不充分で、ここからさらにクリアパーツ、リングの回転をロックする部分を外す必要があります。分解が済んだら、ネジやバネ、細かいパーツはどこかになくしてしまわないように、小皿などにちゃんと分けておきましょう。また、ライダーの顔を別のものに付け替える場合は、シールを剥がす必要があります。経験的には、ドライヤーで温めてからだと比較的綺麗に剥がせる気がします。

塗装が必要な場合は、このタイミングで塗装してしまっても良いと思います。ただ、作業の途中でなんやかんや加工して塗装が一部剥がれてしまうということはよくあるので、気になる方は全て組み上がってから塗装した方がよいと思います。自分は後先考えずにまずはエイヤと作業してしまいましたので、このタイミングで塗装しています。

今回自分が作った万丈ライドウォッチの場合は、基本のクローズのイメージに近づけるため、本体部分(上写真左側)を黒に、リングやら竜頭やらの部分(上写真右側)を青に塗装します。なお、ベースはビルドライドウォッチですが、ジクウドライバーにはクローズとして認識させたいので、認識プレートの部分だけはクローズライドウォッチのものを使用しています。

とりあえずエイヤっとまとめてサーフェイサー。ちなみに自分は塗装に関しては素人というかかなり雑なので、あまり参考にしない方がよいと思います。

サーフェイサーが乾いたら、メタルブラックとメタルブルーのスプレーをそれぞれ吹っかけました。

ここで一個ミスに気づきました。ライドウォッチ本体のこの部分、実はLEDの発光を透過させるためのクリアパーツが入っていたのですが、それに気づかずサーフェイサーやらスプレーを吹っかけてしまいました。この部分は裏のネジを外せば外すことができるので、最初に忘れず分解しておきましょう。

塗装が終わったら、好きなタイミングでラベルシールをクリアパーツとリングパーツに貼り付けます。画像データは、元々のライドウォッチのシールを剥がしてスキャナでスキャンして取得する、あるいは誰かが提供してくれているものを利用させてもらうとして、それをどれぐらいのサイズで印刷すれば良いかはトライ&エラーです。自分の場合は、パワーポイントにいくつか大きさの微妙に違う画像データを並べて普通のA4用紙に印刷してみて、実際それを切ってみて丁度良いサイズが見つかったら、それをラベルシールの用紙に印刷するようにしています。

 

以上で入れ物の準備は完了です。いよいよメインの電子回路の部分に入ります。はじめに、作る回路の全体像を共有しておきます。

前回ご紹介したものとほぼ同じですが、LEDがフルカラーLEDに変わり、フォームチェンジを認識させるためのリードスイッチが追加されています。これらの変化に伴い、ピンの配置も少し変わっているのでご注意ください。普通のライドウォッチを作りたい方は、前回紹介した回路図の方を参照してください。

 

まずはブレッドボード上に上図のとおり配線してみて、プログラムが正しく動作するかを確認しましょう。

ちなみにすみません、リードスイッチを取り付けた状態の写真を撮り損ねました。実際には上図にさらにフォームチェンジ用のリードスイッチも配線する必要があります。また、万丈ライドウォッチ用のプログラムは本記事の最後に掲載しています。

 

動作が確認できたら、ライドウォッチ本体の加工に入っていきます。

 

まずはジクウドライバーとの連携部分、前回のプログラム解説で言うところのSW-1とSW-2の認識部分の作成です。一番最初にいきなりで申し訳ないのですが、ここがこのライドウォッチ作成で一番神経をつかうところです。ここを雑に作ってしまうと、せっかく作ってもジクウドライバーと連動しない、ということになってしまいます。

 

こんな感じで、1.2mm厚のプラ板に穴を開けて、ディテクタスイッチ2つを並行に並べます。プラ板と穴のサイズの目安は以下のようになります。

あくまで目安ですので、最終的には微調整が必要だと思います。

最終的にはこんな感じでプラ板をはめ込んで、SW-1とSW-2が押されたら、それぞれ対応するディテクタスイッチがONになるようにします。が、ここで注意点が2つあります。

まず、2つのディテクタスイッチが、上写真で言うところの左端からの位置ができるだけ揃うように位置を調整する必要があります。というのも、この位置関係がずれてしまうと、ジクウドライバーにライドウォッチをセットしたときに、本来満たされるべき「SW-1とSW-2が同時に押される」という条件が満たされず、代わりに「SW-1の後にSW-2が押される」というような別の条件が満たされてしまう可能性があります。

もう一つの注意点として、SW-1とSW-2が少しでも押されたらディテクタスイッチが反応するよう、ディテクタスイッチの位置を調整する必要があります。ライドウォッチの実物をお持ちの方はよくご存知だと思いますが、このSW-1とSW-2の部分は少しでも触ると反応してしまうぐらい感度が良くて、音声(特にライドウォッチを取り外したときの音)を暴発させてしまうことがよくあると思います。ああいう仕様になっているのはそれ相応の理由があって、

SW-1とSW-2は、ジクウドライバーのこの部分で実際に押し込まれることになるのですが、この押し込みの深さが結構浅いのです。そのため、「スイッチを深く押し込まないと反応しない」というような状態では、ライドウォッチをジクウドライバーにセットしたとしても、スイッチが反応してくれないのです。

そのため、位置決めが済んで、配線の半田付けと(ホットボンドでの)スイッチの位置の固定ができたら、

こんな感じで、他のパーツを組み付けていく前に、ブレッドボード上で「スイッチの同時押しが認識される」「スイッチを軽く押したら反応してくれる」というのを確認しておくことをオススメします。できれば、この状態でジクウドライバーにセットして、ドライバーを回転させたときにスイッチが押されるかを確認するのがベストです。パーツを全部組み付けてから戻ってきて微調整するのは、結構面倒臭いです。

SW-1, 2の感度が鈍い場合は、こんな感じでディテクタスイッチとの接触部分に薄いプラ板を貼ることで、ある程度は感度を調整できます。

「SW-1, 2を押すとディテクタスイッチは押されるけど、SW-1, 2が押されたままになってしまう」というときは、ディテクタスイッチがSW-1, 2に近づき過ぎているので、プラ板などでディタクタスイッチの高さを微調整してあげましょう。かといって、ディテクタスイッチの位置を高くし過ぎると、今度はSW-1, SW-2が押し込まれてもディテクタスイッチが反応しない…ということにもなるので、ここはもう、辛抱強く微調整する必要があります。

この微調整が辛過ぎる、という方は、元々のDX用基板のディテクタスイッチ部分だけを基板ごと切り離して持ってくる、という手もあるかもしれません。自分は試していませんが。

 

SW-1, 2の部分の処理が済んだら、次はその上に、配線済みのDFPlayerを被せます。DFPlayerのスピーカーには、元々ライドウォッチに組み込まれていたスピーカーと接続しています。

そのまま被せると、最後にライドウォッチの蓋が閉じなくなってしまうので、ピンを全体的に少し短く切ってあげましょう。あんまり切り過ぎると、先にセットしたディテクタスイッチとモロに干渉してしまうので、ほどほどに。

Tipsですが、DFPlayerには2つのGND端子があります。この2つは内部的には当然繋がっているので、DFPlayerの一つのGNDを後でArduino基板のGNDに繋いでしまえば、先ほどのディテクタスイッチのGND側の配線は、Arduino基板ではなくDFPlayerのもう一方のGNDに繋いでしまって問題ありません。こうすることで、配線数が増えがちなGND端子への接続を少し分散させることができます。

 

続いて、竜頭スイッチ(SW-C)の処理です。こちらは簡単。

「やわらかいタクトスイッチ」に配線したものを1.2mmプラ板にホットボンドで固定して、

元々LEDの基板が入っていたところにはめ込みます。竜頭スイッチ側の方は元々の出っ張り部分をカットして、その部分に薄いプラ板を貼り付けておけば、やわらかいタクトスイッチを良い感じに押せるようになります。

 

ここからは、本体の蓋側の方の処理になります。まずはフルカラーLEDの処理です。

最終的にこんな感じで、フルカラーLEDがライドウォッチの蓋側の小さな窓(クリアーパーツがあったところ)から顔を出してほしいので、

フルカラーLEDをギリギリまでカットします。これぐらいカットしてしまっても、配線さえ正しければちゃんと動きます。

本体裏側から、カットしたフルカラーLEDを差し込みます。

おそらくブカブカになってしまうので、小さく切ったプラ板をスペーサーとして差し込んでフルカラーLEDを固定させます。これでフルカラーLEDの処理はとりあえず終了です。

 

続いて、フォームチェンジ用のリードスイッチの処理です。この処理は、フォームチェンジ機能が不要であればいりません。

リードスイッチを反応させるためのネオジム磁石はリングの突起部分に取り付けることになるのですが、いくらネオジム磁石が強力といえども、本体内側にあるリードスイッチを反応させようと思うと結構距離が厳しくなります。

 

リードスイッチの対向のネオジム磁石はこんな感じでリングにはめ込むことになるのですが、モノによってはスッと入らず、ニッパやヤスリで多少穴を大きくしてやる必要があります。これが面倒だからといって小さめのネオジム磁石にすると、今度は磁力が弱くなってリードスイッチが反応しない…ということもあり得るので、ここは多少トライ&エラーが必要かもしれません。

リードスイッチを固定してしまう前に、仮で位置決めし、リングの回転に応じてリードスイッチが反応するかどうかを必ず確認するようにしましょう。反応することが確認できたら、ホットボンドなどでリードスイッチを固定します。なお、リードスイッチは非常に脆い部品ですので、取り扱いに充分ご注意ください。

 

 

本体蓋側に必要な部品はフルカラーLEDとリードスイッチの2つだけですので、それらの取り付けが終わったら、本体下側と接続するためのピンヘッダを作ります。GNDをフルカラーLEDとリードスイッチでまとめてしまえば、ピンヘッダは4本になります。

 

さて、本体下側に戻り、Arduino基板に諸々配線していきます。

いきなり完成形で申し訳ありませんが、配線はこんな感じになります。写真では見辛いですが、最初の回路図の通りです。本体蓋部との接続が必要な部分は、ピンソケットにまとめています。GNDのとりかたは、できるだけArduino基板のGND端子で全部をまとめてしまわないよう、DFPlayerのGNDを活用するなどして、できるだけ分散させるようにしています。

というのも、実は、最初に作ったときにやらかしてしまっていて、GND線とプラス線をArduino基板上の端子にまとめ過ぎて、Arduino基板上でそれらが接触してショートし、基板とDFPlayerを壊してしまいました。そのため、実は一回、ほぼ作り直しになっています。

こちらが最初に作成したときの配線になります。GND端子とプラス端子(RAW端子)がArduino Pro mini上では隣り合わせであるにも関わらず、上図のように危険極まりないことをしてしまいました。反省。

 

気を取り直して、少し細部をみます。

電源スイッチ(スライドスイッチ)は、この位置に入れています。

この部分は元々スリット状になっているので、少し加工してやれば、スライドスイッチが顔を出せるようになります。

リチウムイオンポリマー充電池は、最小のものを用意して、コードを巻いてこの位置に。細めのピンソケットを使えば、リチウムイオンポリマー充電池用のコネクタ(2ピンPHコネクタ)を使わずとも電力をとれます。

 

全ての配線ができていることを確認したら、本体蓋部と下部のピンヘッダ・ピンソケットを接続して、本体を閉じる前に一度電源スイッチを入れてみましょう。

この状態で、まずは正しく動作するかの確認です。確認ができたら、本体を閉じてネジ止めし、再度動作するかを確認しましょう。

自分の経験的に「本体を閉じる前は正しく動作していたのに、本体を閉じると動作しなくなる」ということは、とてもよくあります。この現象の原因はほぼ100%、接触不良によるものです。つまり、本体を閉じる前は配線としては問題なかったが、本体を閉じると、本体内で無理な力が局所的にかかってしまい、リード線の断線や他の線との接触、半田外れが発生してしまうということです。対策としては、ピンソケットやピンヘッダ、基板端子部など、半田付けが発生しているところをことごとくホットボンド(グルーガン)で保護してしまう、という手があります。上の方の写真でも、透明なゲル状のものがArduinoの端子やピンヘッダ・ピンソケットについているのが見えると思います。これをやっておくと、多少力がかかるぐらいでは、断線や半田の外れは起こらなくなります。まあ、そもそもは内部に局所的な力が発生しないように、余裕を持った設計をするのが一番なのですが…

 

さて、ここまでくればほとんど終わったようなもので、あとは最後の仕上げです。

 

フルカラーLEDはこんな感じで顔を出しているのですが、光が直進的過ぎて、クリアパーツが思ったより綺麗に発光してくれないと感じる場合があります。

その場合は、フルカラーLEDとクリアパーツの間に、光拡散キャップを四角く切ったものを挟んであげましょう。これで、光がうまく混ざって拡散するようになります。

 

最後に、リングパーツをはめ込んで完成です。おつかれさまでした。

 

ということで、私なりのオリジナルライドウォッチの作成方法を全てご紹介しました。結構力技で押し切っている部分もありますので(特にSW-1, 2の処理)、本記事を見て、「ここはこう処理した方がもっとスマートだ!」というやり方を考案された方がおられましたら、是非是非教えて頂ければと思います。

 

最後に、私の万丈ライドウォッチのソースコードを公開して終わりにしたいと思います。前回申し上げましたとおり、このコードについては特に説明は加えませんが、前回公開したソースコードを理解された方であれば、フォームチェンジのためにフルカラーLEDとリードスイッチの処理が追加されているだけですので、問題なく理解できると思います。
 

#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <Adafruit_NeoPixel.h>

SoftwareSerial ss_mp3_player(2, 3); // RX, TX
#define LED_PIN  4
#define SW_C_PIN 5
#define SW_1_PIN 6
#define SW_2_PIN 7
#define REED_PIN 8

#define LOOP_INTERVAL_MS 20

#define ON  LOW
#define OFF HIGH
#define N_BUTTON 3
const uint8_t OFF_OFF_OFF[] = {OFF, OFF, OFF};
const uint8_t ON_OFF_OFF[]  = {ON,  OFF, OFF};
const uint8_t OFF_ON_OFF[]  = {OFF, ON,  OFF};
const uint8_t OFF_OFF_ON[]  = {OFF, OFF, ON };
const uint8_t ON_ON_OFF[]   = {ON,  ON,  OFF};
const uint8_t ON_OFF_ON[]   = {ON,  OFF, ON };
const uint8_t OFF_ON_ON[]   = {OFF, ON,  ON };
const uint8_t ON_ON_ON[]    = {ON,  ON,  ON };

#define STATE_SINGLE_A 1
#define STATE_SINGLE_B 2
#define STATE_READY_WP 3
#define STATE_WEAPON   4
#define STATE_READY_CH 5
#define STATE_CHANGED  6
#define STATE_READY_CR 7
#define STATE_CRITICAL 8

#define SIDE_NONE 0
#define SIDE_ARMOR_TIME 1
#define SIDE_RIDER_TIME 2

#define FORM_STATE_CROSS_Z 0
#define FORM_STATE_CHARGE  1
#define FORM_STATE_MAGMA   2

uint8_t prev_state = STATE_SINGLE_A;
uint8_t state      = STATE_SINGLE_A;
uint8_t prev_side  = SIDE_NONE;
uint8_t side       = SIDE_NONE;
uint8_t prev_relay = OFF;
uint8_t relay      = OFF;
uint8_t form_state = FORM_STATE_CROSS_Z;
uint8_t rider_time_counter = 0;
uint8_t armor_time_counter = 0;
uint8_t form_change_counter = 0;

uint8_t prev_sw[]  = {OFF, OFF, OFF};
uint8_t sw[] = {OFF, OFF, OFF};

//--------------------------------------------------------------------------//

// 効果音処理

#define SOUND_START 1
#define SOUND_EJECT 2

#define SOUND_CHANGE_CROSS_Z          3
#define SOUND_SINGLE_A_CROSS_Z        4
#define SOUND_SINGLE_B_CROSS_Z        5
#define SOUND_RIDER_TIME_CROSS_Z      6
#define SOUND_ARMOR_TIME_CROSS_Z      7
#define SOUND_WEAPON_CROSS_Z          8
#define SOUND_CRITICAL_READY_CROSS_Z  9
#define SOUND_CRITICAL_CROSS_Z       10

#define SOUND_CHANGE_CHARGE         11
#define SOUND_SINGLE_A_CHARGE       12
#define SOUND_SINGLE_B_CHARGE       13
#define SOUND_RIDER_TIME_CHARGE     14
#define SOUND_ARMOR_TIME_CHARGE     15
#define SOUND_WEAPON_CHARGE         16
#define SOUND_CRITICAL_READY_CHARGE 17
#define SOUND_CRITICAL_CHARGE       18

#define SOUND_CHANGE_MAGMA         19
#define SOUND_SINGLE_A_MAGMA       20
#define SOUND_SINGLE_B_MAGMA       21
#define SOUND_RIDER_TIME_MAGMA     22
#define SOUND_ARMOR_TIME_MAGMA     23
#define SOUND_WEAPON_MAGMA         24
#define SOUND_CRITICAL_READY_MAGMA 25
#define SOUND_CRITICAL_MAGMA       26

#define ARMOR_TIME_WAIT 6500
#define RIDER_TIME_WAIT 1000
#define CRITICAL_WAIT_SHORT 1000
#define CRITICAL_WAIT_LONG  2000

unsigned long sound_wait_start_time = 0;
boolean is_armor_time_waiting = false;
boolean is_rider_time_waiting = false;
boolean is_armor_time_critical_waiting = false;
boolean is_rider_time_critical_waiting = false;

DFRobotDFPlayerMini mp3_player;

void play_sound(){
  if(prev_state != state){
    switch(state){
    case STATE_SINGLE_A:
      switch(prev_state){
      case STATE_SINGLE_B:
        switch(form_state){
        case FORM_STATE_CROSS_Z:        mp3_player.playMp3Folder(SOUND_SINGLE_A_CROSS_Z); break;
        case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_SINGLE_A_CHARGE); break;
        case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_SINGLE_A_MAGMA); break;
        default: ;
        }
        break;
      case STATE_READY_WP:
      case STATE_WEAPON:
      case STATE_READY_CH:
      case STATE_CHANGED:
      case STATE_READY_CR:
      case STATE_CRITICAL:
        mp3_player.playMp3Folder(SOUND_EJECT);
        break;
      default:
        ;
      }
      break;
    case STATE_SINGLE_B:
      switch(form_state){
      case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_SINGLE_B_CROSS_Z); break;
      case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_SINGLE_B_CHARGE); break;
      case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_SINGLE_B_MAGMA); break;
      default: ;
      }
      break;
    case STATE_READY_WP:
      if(prev_state != STATE_WEAPON){
        mp3_player.pause();
      }
      break;
    case STATE_WEAPON:
      switch(form_state){
      case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_WEAPON_CROSS_Z); break;
      case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_WEAPON_CHARGE); break;
      case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_WEAPON_MAGMA); break;
      default: ;
      }
      break;
    case STATE_READY_CH:
      mp3_player.pause();
      break;
    case STATE_CHANGED:
      if(side == SIDE_RIDER_TIME){
        sound_wait_start_time = millis();
        is_rider_time_waiting = true;
      }else if(side == SIDE_ARMOR_TIME){
        sound_wait_start_time = millis();
        is_armor_time_waiting = true;
      }
      break;
    case STATE_READY_CR:
      switch(form_state){
      case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_CRITICAL_READY_CROSS_Z); break;
      case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_CRITICAL_READY_CHARGE); break;
      case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_CRITICAL_READY_MAGMA); break;
      default: ;
      }
      break;
    case STATE_CRITICAL:
      if(side == SIDE_RIDER_TIME){
        sound_wait_start_time = millis();
        is_rider_time_critical_waiting = true;
      }else if(side == SIDE_ARMOR_TIME){
        sound_wait_start_time = millis();
        is_armor_time_critical_waiting = true;
      }
      break;
    default:
      ;
    }
  }else{
    unsigned long now = millis();
    if(is_rider_time_waiting){
      if(now - sound_wait_start_time >= RIDER_TIME_WAIT){
        switch(form_state){
        case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_RIDER_TIME_CROSS_Z); break;
        case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_RIDER_TIME_CHARGE); break;
        case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_RIDER_TIME_MAGMA); break;
        default: ;
        }
        is_rider_time_waiting = false;
      }
    }else if(is_armor_time_waiting){
      if(now - sound_wait_start_time >= ARMOR_TIME_WAIT){
        switch(form_state){
        case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_ARMOR_TIME_CROSS_Z); break;
        case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_ARMOR_TIME_CHARGE); break;
        case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_ARMOR_TIME_MAGMA); break;
        default: ;
        }
        is_armor_time_waiting = false;
      }
    }else if(is_rider_time_critical_waiting){
      if(now - sound_wait_start_time >= CRITICAL_WAIT_LONG){
        switch(form_state){
        case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_CRITICAL_CROSS_Z); break;
        case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_CRITICAL_CHARGE); break;
        case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_CRITICAL_MAGMA); break;
        default: ;
        }
        is_rider_time_critical_waiting = false;
      }
    }else if(is_armor_time_critical_waiting){
      if(now - sound_wait_start_time >= CRITICAL_WAIT_SHORT){
        switch(form_state){
        case FORM_STATE_CROSS_Z:mp3_player.playMp3Folder(SOUND_CRITICAL_CROSS_Z); break;
        case FORM_STATE_CHARGE: mp3_player.playMp3Folder(SOUND_CRITICAL_CHARGE); break;
        case FORM_STATE_MAGMA:  mp3_player.playMp3Folder(SOUND_CRITICAL_MAGMA); break;
        default: ;
        }
        is_armor_time_critical_waiting = false;
      }
    }
  }
}

//--------------------------------------------------------------------------//

// 発光処理

#define LED_COUNT_MAX 1500 // LOOP_INTERVAL_MSが20msで、30sまでの発光定義を想定
#define N_LED    1

#define COLOR_R_CROSS_Z   0
#define COLOR_G_CROSS_Z   0
#define COLOR_B_CROSS_Z 255
#define COLOR_R_CHARGE  255
#define COLOR_G_CHARGE  255
#define COLOR_B_CHARGE    0
#define COLOR_R_MAGMA   255
#define COLOR_G_MAGMA   102
#define COLOR_B_MAGMA     0

uint16_t led_counter = LED_COUNT_MAX;
unsigned long blink_time = 0;
unsigned long prev_blink_time = 0;
unsigned long inc_dim_start_time = 0;
boolean is_lighting = false;
boolean is_inc = false;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_LED, LED_PIN, NEO_GRB);

void led_base_pattern_on(uint8_t r, uint8_t g, uint8_t b){
  pixels.setPixelColor(0, pixels.Color(r,g,b));
}

void led_base_pattern_off(){
  pixels.setPixelColor(0, pixels.Color(0,0,0));
}

void led_base_pattern_blink(uint8_t r, uint8_t g, uint8_t b, int interval_ms){
  unsigned long now = millis();
  if(now - prev_blink_time >= interval_ms){
    if(is_lighting){
      pixels.setPixelColor(0, pixels.Color(0,0,0));
    }else{
      pixels.setPixelColor(0, pixels.Color(r,g,b));
    }
    is_lighting = !is_lighting;
    prev_blink_time = now;
  }
}

void led_base_pattern_inc(uint8_t r, uint8_t g, uint8_t b, int interval_ms, uint8_t steps){
  unsigned long now = millis();
  if(inc_dim_start_time == 0){
    inc_dim_start_time = now;
  }
  int ms_per_step = interval_ms / steps;
  int current_step = (now - inc_dim_start_time) / ms_per_step;
  uint8_t r_step = r/steps;
  uint8_t g_step = g/steps;
  uint8_t b_step = b/steps;
  pixels.setPixelColor(0, pixels.Color(r_step*current_step, g_step*current_step, b_step*current_step));
  if(now - inc_dim_start_time >= interval_ms){
    inc_dim_start_time = 0;
  }
}

void led_base_pattern_dim(uint8_t r, uint8_t g, uint8_t b, int interval_ms, uint8_t steps){
  unsigned long now = millis();
  if(inc_dim_start_time == 0){
    inc_dim_start_time = now;
  }
  int ms_per_step = interval_ms / steps;
  int current_step = (now - inc_dim_start_time) / ms_per_step;
  uint8_t r_step = r/steps;
  uint8_t g_step = g/steps;
  uint8_t b_step = b/steps;
  pixels.setPixelColor(0, pixels.Color(r_step*(steps-current_step), g_step*(steps-current_step), b_step*(steps-current_step)));
  if(now - inc_dim_start_time >= interval_ms){
    inc_dim_start_time = 0;
  }
}

void led_base_pattern_blink_slowly(uint8_t r, uint8_t g, uint8_t b, int interval_ms, uint8_t steps){
  unsigned long now = millis();
  if(inc_dim_start_time == 0){
    inc_dim_start_time = now;
  }
  int ms_per_step = interval_ms / steps;
  int current_step = (now - inc_dim_start_time) / ms_per_step;
  uint8_t r_step = r/steps;
  uint8_t g_step = g/steps;
  uint8_t b_step = b/steps;
  if(is_inc){
    pixels.setPixelColor(0, pixels.Color(r_step*current_step, g_step*current_step, b_step*current_step));
  }else{
    pixels.setPixelColor(0, pixels.Color(r_step*(steps-current_step), g_step*(steps-current_step), b_step*(steps-current_step)));
  }
  if(now - inc_dim_start_time >= interval_ms){
    is_inc = !is_inc;
    inc_dim_start_time = 0;
  }
}

//----------------------//

void led_pattern_single_a_cross_z(uint16_t led_counter_ms){ // 起動音+解説+「クローズだ!」
  if(led_counter_ms <= 600){                                 led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <=  1800){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 1000, 10);}
  else if(1800 < led_counter_ms && led_counter_ms <=  7200){ led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
  else if(7200 < led_counter_ms && led_counter_ms <=  9400){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 90);}
  else if(9400 < led_counter_ms && led_counter_ms <= 10000){ led_base_pattern_off();}
  else{                                                      led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_single_a_charge(uint16_t led_counter_ms){ // 起動音+解説+「万丈だ」
  if(led_counter_ms <= 600){                                   led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 80);}
  else if(  600 < led_counter_ms && led_counter_ms <=  1600){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1000, 10);}
  else if( 1600 < led_counter_ms && led_counter_ms <= 11100){ led_base_pattern_blink_slowly(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1200, 12);}
  else if(11100 < led_counter_ms && led_counter_ms <= 15300){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 90);}
  else if(15300 < led_counter_ms && led_counter_ms <= 16000){ led_base_pattern_off();}
  else{                                                       led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_single_a_magma(uint16_t led_counter_ms){ // 起動音+解説+「俺だ」
  if(led_counter_ms <= 600){                                 led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1800){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1200, 10);}
  else if(1800 < led_counter_ms && led_counter_ms <= 3000){ led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
  else if(3000 < led_counter_ms && led_counter_ms <= 5200){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 90);}
  else if(5200 < led_counter_ms && led_counter_ms <= 5900){ led_base_pattern_off();}
  else{                                                      led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_single_b_cross_z(uint16_t led_counter_ms){ // 起動音+起動音+「クローズ!」
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 3200){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_single_b_charge(uint16_t led_counter_ms){ // 起動音+起動音+「クローズチャージ!」
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 3100){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 40);}
  else if(3100 < led_counter_ms && led_counter_ms <= 3750){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 650, 10);}
  else{                                                     led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_single_b_magma(uint16_t led_counter_ms){ // 起動音+起動音+「クローズマグマ!」
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 3100){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 40);}
  else if(3100 < led_counter_ms && led_counter_ms <= 4400){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA,1300, 10);}
  else{                                                     led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_weapon_cross_z(uint16_t led_counter_ms){ // 「クローズ!」
  if(led_counter_ms <= 300){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 40);}
  else{                      led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_weapon_charge(uint16_t led_counter_ms){ // 「クローズチャージ!」
  if(led_counter_ms <= 800){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 40);}
  else{                      led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_weapon_magma(uint16_t led_counter_ms){ // 「クローズマグマ!」
  if(led_counter_ms <= 1500){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 40);}
  else{                       led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_rider_time_cross_z(uint16_t led_counter_ms){
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <= 1900){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 800, 10);}
  else if(1900 < led_counter_ms && led_counter_ms <= 2800){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 900, 10);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_rider_time_charge(uint16_t led_counter_ms){
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <= 1900){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 800, 10);}
  else if(1900 < led_counter_ms && led_counter_ms <= 2800){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 900, 10);}
  else if(2800 < led_counter_ms && led_counter_ms <= 6800){ led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
  else if(6800 < led_counter_ms && led_counter_ms <= 7800){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 60);}
  else{                                                     led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_rider_time_magma(uint16_t led_counter_ms){
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <=  1900){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 800, 10);}
  else if(1900 < led_counter_ms && led_counter_ms <=  2800){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 900, 10);}
  else if(2800 < led_counter_ms && led_counter_ms <=  7300){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA,180);}
  else if(7300 < led_counter_ms && led_counter_ms <=  9000){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 60);}
  else if(9000 < led_counter_ms && led_counter_ms <=  9200){ led_base_pattern_off();}
  else if(9200 < led_counter_ms && led_counter_ms <= 11400){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 2200, 20);}
  else{                                                      led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_armor_time_cross_z(uint16_t led_counter_ms){
  if(led_counter_ms <= 6600){                               led_base_pattern_off();}
  else if(6600 < led_counter_ms && led_counter_ms <= 7400){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 800, 10);}
  else if(7400 < led_counter_ms && led_counter_ms <= 8600){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 1200, 10);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_armor_time_charge(uint16_t led_counter_ms){
  if(led_counter_ms <= 6600){                                 led_base_pattern_off();}
  else if( 6600 < led_counter_ms && led_counter_ms <=  7400){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 800, 10);}
  else if( 7400 < led_counter_ms && led_counter_ms <=  8600){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1200, 10);}
  else if( 8600 < led_counter_ms && led_counter_ms <= 12600){ led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
  else if(12600 < led_counter_ms && led_counter_ms <= 13600){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 60);}
  else{                                                       led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_armor_time_magma(uint16_t led_counter_ms){
  if(led_counter_ms <= 6600){                                 led_base_pattern_off();}
  else if( 6600 < led_counter_ms && led_counter_ms <=  7400){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 800, 10);}
  else if( 7400 < led_counter_ms && led_counter_ms <=  8600){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1200, 10);}
  else if( 8600 < led_counter_ms && led_counter_ms <= 13100){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA,180);}
  else if(13100 < led_counter_ms && led_counter_ms <= 14800){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 60);}
  else if(14800 < led_counter_ms && led_counter_ms <= 15000){ led_base_pattern_off();}
  else if(15000 < led_counter_ms && led_counter_ms <= 17200){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 2200, 20);}
  else{                                                       led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_ready_critical_cross_z(uint16_t led_counter_ms){ // 起動音+「クローズ!」+待機
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 3100){ led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
  else{                                                     led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 800);}
}

void led_pattern_ready_critical_charge(uint16_t led_counter_ms){ // 起動音+「クローズチャージ!」+待機
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 2250){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 650, 10);}
  else if(2250 < led_counter_ms && led_counter_ms <= 3450){ led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
  else{                                                     led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 800);}
}

void led_pattern_ready_critical_magma(uint16_t led_counter_ms){ // 起動音+「クローズマグマ!」+待機
  if(led_counter_ms <= 600){                                led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 80);}
  else if( 600 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1000, 10);}
  else if(1600 < led_counter_ms && led_counter_ms <= 2900){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1300, 10);}
  else if(2900 < led_counter_ms && led_counter_ms <= 4400){ led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
  else{                                                     led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 800);}
}

//----------------------//

void led_pattern_critical_long_cross_z(uint16_t led_counter_ms){ // 「ドラゴニック!」
  if(led_counter_ms <= 2100){                               led_base_pattern_off();}
  else if(2100 < led_counter_ms && led_counter_ms <= 2600){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_critical_long_charge(uint16_t led_counter_ms){ // 「ドラゴンジェリー!」
  if(led_counter_ms <= 2100){                               led_base_pattern_off();}
  else if(2100 < led_counter_ms && led_counter_ms <= 2700){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_critical_long_magma(uint16_t led_counter_ms){ // 「ボルケニック!」
  if(led_counter_ms <= 2100){                               led_base_pattern_off();}
  else if(2100 < led_counter_ms && led_counter_ms <= 2600){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_critical_short_cross_z(uint16_t led_counter_ms){ // 「ドラゴニック!」
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_critical_short_charge(uint16_t led_counter_ms){ // 「ドラゴンジェリー!」
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <= 1700){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_critical_short_magma(uint16_t led_counter_ms){ // 「ボルケニック!」
  if(led_counter_ms <= 1100){                               led_base_pattern_off();}
  else if(1100 < led_counter_ms && led_counter_ms <= 1600){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void led_pattern_change_cross_z(uint16_t led_counter_ms){ // ドライバー装填音 + 「変身!」
  if(led_counter_ms <= 900){                               led_base_pattern_dim(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 900, 10);}
  else if(900 < led_counter_ms && led_counter_ms <= 1400){ led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z);}
}

void led_pattern_change_charge(uint16_t led_counter_ms){ // ドライバー装填音 + 「今の俺は...負ける気がしねえ!」
  if(led_counter_ms <= 1100){                               led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1100, 10);}
  else if(1100 < led_counter_ms && led_counter_ms <= 2300){ led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
  else if(2300 < led_counter_ms && led_counter_ms <= 3500){ led_base_pattern_dim(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 1200, 10);}
  else if(3500 < led_counter_ms && led_counter_ms <= 4500){ led_base_pattern_blink(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE);}
}

void led_pattern_change_magma(uint16_t led_counter_ms){ //  ドライバー装填音 + 「俺のマグマが迸る!」
  if(led_counter_ms <= 1200){                               led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 1200, 10);}
  else if(1200 < led_counter_ms && led_counter_ms <= 2600){ led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
  else if(2600 < led_counter_ms && led_counter_ms <= 2800){ led_base_pattern_dim(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 200, 5);}
  else if(2800 < led_counter_ms && led_counter_ms <= 3400){ led_base_pattern_blink(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA, 40);}
  else{                                                     led_base_pattern_on(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA);}
}

//----------------------//

void flash_led(){

  if(prev_state != state){
    if(prev_state != STATE_SINGLE_B && state == STATE_SINGLE_A){
      led_counter = LED_COUNT_MAX; // 発光させないように、カウントの上限値にする
    }else if((prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B) && state == STATE_READY_WP){
      led_counter = LED_COUNT_MAX; // 発光させないように、カウントの上限値にする
    }else if(prev_state == STATE_WEAPON && state == STATE_READY_WP){
      ; // 発光を継続させるためにカウントをリセットしない
    }else{
      led_counter = 0; // 基本的に状態遷移が発生するとカウントをリセットする
    }
  }else if(prev_side != side){
    led_counter = 0;
  }

  uint16_t led_counter_ms = led_counter * LOOP_INTERVAL_MS; // LEDはms単位で制御

  switch(state){
  case STATE_SINGLE_A:
    switch(form_state){
    case FORM_STATE_CROSS_Z: led_pattern_single_a_cross_z(led_counter_ms); break;
    case FORM_STATE_CHARGE:  led_pattern_single_a_charge(led_counter_ms);  break;
    case FORM_STATE_MAGMA:   led_pattern_single_a_magma(led_counter_ms);   break;
    default: ;
    }
    break;
  case STATE_SINGLE_B:
    switch(form_state){
    case FORM_STATE_CROSS_Z: led_pattern_single_b_cross_z(led_counter_ms); break;
    case FORM_STATE_CHARGE:  led_pattern_single_b_charge(led_counter_ms);  break;
    case FORM_STATE_MAGMA:   led_pattern_single_b_magma(led_counter_ms);   break;
    default: ;
    }
    break;
  case STATE_READY_WP:
  case STATE_WEAPON:
    switch(form_state){
    case FORM_STATE_CROSS_Z: led_pattern_weapon_cross_z(led_counter_ms); break;
    case FORM_STATE_CHARGE:  led_pattern_weapon_charge(led_counter_ms);  break;
    case FORM_STATE_MAGMA:   led_pattern_weapon_magma(led_counter_ms);   break;
    default: ;
    }
    break;
  case STATE_READY_CH:
    switch(form_state){
    case FORM_STATE_CROSS_Z: led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 800); break;
    case FORM_STATE_CHARGE:  led_base_pattern_blink(COLOR_R_CHARGE,  COLOR_G_CHARGE,  COLOR_B_CHARGE,  800); break;
    case FORM_STATE_MAGMA:   led_base_pattern_blink(COLOR_R_MAGMA,   COLOR_G_MAGMA,   COLOR_B_MAGMA,   800); break;
    default: ;
    }
    break;
  case STATE_CHANGED:
    if(side == SIDE_NONE){
      switch(form_state){
      case FORM_STATE_CROSS_Z: led_base_pattern_blink(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z, 800); break;
      case FORM_STATE_CHARGE:  led_base_pattern_blink(COLOR_R_CHARGE,  COLOR_G_CHARGE,  COLOR_B_CHARGE,  800); break;
      case FORM_STATE_MAGMA:   led_base_pattern_blink(COLOR_R_MAGMA,   COLOR_G_MAGMA,   COLOR_B_MAGMA,   800); break;
      default: ;
      }
    }else if(side == SIDE_ARMOR_TIME){
      switch(form_state){
      case FORM_STATE_CROSS_Z: led_pattern_armor_time_cross_z(led_counter_ms); break;
      case FORM_STATE_CHARGE:  led_pattern_armor_time_charge(led_counter_ms);  break;
      case FORM_STATE_MAGMA:   led_pattern_armor_time_magma(led_counter_ms);   break;
      default: ;
      }
    }else if(side == SIDE_RIDER_TIME){
      switch(form_state){
      case FORM_STATE_CROSS_Z: led_pattern_rider_time_cross_z(led_counter_ms); break;
      case FORM_STATE_CHARGE:  led_pattern_rider_time_charge(led_counter_ms);  break;
      case FORM_STATE_MAGMA:   led_pattern_rider_time_magma(led_counter_ms);   break;
      default: ;
      }
    }
    break;
  case STATE_READY_CR:
    switch(form_state){
    case FORM_STATE_CROSS_Z: led_pattern_ready_critical_cross_z(led_counter_ms); break;
    case FORM_STATE_CHARGE:  led_pattern_ready_critical_charge(led_counter_ms);  break;
    case FORM_STATE_MAGMA:   led_pattern_ready_critical_magma(led_counter_ms);   break;
    default: ;
    }
    break;
  case STATE_CRITICAL:
    if(side == SIDE_ARMOR_TIME){
      switch(form_state){
      case FORM_STATE_CROSS_Z:led_pattern_critical_short_cross_z(led_counter_ms); break;
      case FORM_STATE_CHARGE: led_pattern_critical_short_charge(led_counter_ms);  break;
      case FORM_STATE_MAGMA:  led_pattern_critical_short_magma(led_counter_ms);   break;
      default: ;
      }
    }else if(side == SIDE_RIDER_TIME){
      switch(form_state){
      case FORM_STATE_CROSS_Z:led_pattern_critical_long_cross_z(led_counter_ms); break;
      case FORM_STATE_CHARGE: led_pattern_critical_long_charge(led_counter_ms);  break;
      case FORM_STATE_MAGMA:  led_pattern_critical_long_magma(led_counter_ms);   break;
      default: ;
      }
    }
    break;
  default:
    ;
  }

  if(led_counter < LED_COUNT_MAX){
    led_counter++;
  }

  pixels.show();
}

//--------------------------------------------------------------------------//

// リセット処理

void reset_rider_time_counter(){
  rider_time_counter = 0;
}

void reset_armor_time_counter(){
  armor_time_counter = 0;
}

void reset_all(){
  switch(form_state){
  case FORM_STATE_CROSS_Z: pixels.setPixelColor(0, pixels.Color(COLOR_R_CROSS_Z, COLOR_G_CROSS_Z, COLOR_B_CROSS_Z)); break;
  case FORM_STATE_CHARGE: pixels.setPixelColor(0, pixels.Color(COLOR_R_CHARGE, COLOR_G_CHARGE, COLOR_B_CHARGE)); break;
  case FORM_STATE_MAGMA: pixels.setPixelColor(0, pixels.Color(COLOR_R_MAGMA, COLOR_G_MAGMA, COLOR_B_MAGMA)); break;
  default: ;
  }
  reset_rider_time_counter();
  reset_armor_time_counter();
  is_armor_time_waiting = false;
  is_rider_time_waiting = false;
  is_armor_time_critical_waiting = false;
  is_rider_time_critical_waiting = false;
  led_counter = LED_COUNT_MAX;
}

//--------------------------------------------------------------------------//

// 起動処理

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(SW_C_PIN, INPUT_PULLUP);
  pinMode(SW_1_PIN, INPUT_PULLUP);
  pinMode(SW_2_PIN, INPUT_PULLUP);
  pinMode(REED_PIN, INPUT_PULLUP);

  // ---------- MP3プレイヤーセットアップ ----------
  ss_mp3_player.begin(9600);
  if (!mp3_player.begin(ss_mp3_player)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin music_player:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("mp3_player online."));
  mp3_player.setTimeOut(500); //Set serial communictaion time out 500ms
  mp3_player.volume(22);  //Set volume value (0~30).

  // ---------- 初期状態取得 ----------
  relay = prev_relay = digitalRead(REED_PIN);

  // ---------- 起動エフェクト ----------
  mp3_player.playMp3Folder(SOUND_START);
  pixels.setPixelColor(0, pixels.Color(0,0,255));
  pixels.show();
}

//--------------------------------------------------------------------------//

// メイン処理

void loop() {
  sw[0] = digitalRead(SW_C_PIN);
  sw[1] = digitalRead(SW_1_PIN);
  sw[2] = digitalRead(SW_2_PIN);

  prev_state = state;
  prev_side  = side;

  if(memcmp(prev_sw, OFF_OFF_OFF, N_BUTTON) == 0){
    if(memcmp(sw, ON_OFF_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A){
        state = STATE_SINGLE_B;
      }else if(prev_state == STATE_SINGLE_B){
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, OFF_ON_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_WP;
      }
    }else if(memcmp(sw, OFF_OFF_ON, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_OFF,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_ON,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_ON,  N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_CH;
      }
    }else if(memcmp(sw, ON_ON_ON,   N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, ON_OFF_OFF, N_BUTTON) == 0){
    if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_OFF,  N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_WP;
      }
    }else if(memcmp(sw, ON_OFF_ON,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_OFF, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_OFF_ON, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_ON,   N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_CH;
      }
    }else if(memcmp(sw, OFF_ON_ON,  N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, OFF_ON_OFF, N_BUTTON) == 0){
    if(memcmp(sw, ON_ON_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED){
        reset_all();
        state = STATE_READY_CR;
      }else if(prev_state == STATE_READY_CR){
        reset_all();
        prev_state = STATE_CHANGED; // 擬似的に状態変化を起こす
        state = STATE_READY_CR;
      }
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED || prev_state == STATE_READY_WP || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, OFF_ON_ON,   N_BUTTON) == 0){
      if(prev_state == STATE_READY_WP){
        state = STATE_WEAPON;
      }else if(prev_state == STATE_READY_CH || prev_state == STATE_CHANGED){
        rider_time_counter++;
        if(rider_time_counter == 2){
          prev_state = STATE_READY_CH; // 擬似的に状態変化を起こす
          state = STATE_CHANGED;
          side  = SIDE_RIDER_TIME;
        }
      }else if(prev_state == STATE_READY_CR){
        rider_time_counter++;
        if(rider_time_counter == 2){
          state = STATE_CRITICAL;
          side  = SIDE_RIDER_TIME;
        }
      }
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_ON,    N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_OFF_ON,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_ON,   N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, OFF_OFF_ON, N_BUTTON) == 0){
    if(memcmp(sw, ON_OFF_ON, N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A){
        state = STATE_SINGLE_B;
      }else if(prev_state == STATE_SINGLE_B){
        state = STATE_SINGLE_A;
      }else if(prev_state == STATE_CHANGED){
        reset_all();
        state = STATE_READY_CR;
      }else if(prev_state == STATE_READY_CR){
        reset_all();
        prev_state = STATE_CHANGED; // 擬似的に状態変化を起こす
        state = STATE_READY_CR;
      }
    }else if(memcmp(sw, OFF_ON_ON,   N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_CH;
      }else if(prev_state == STATE_READY_CH || prev_state == STATE_CHANGED){
        armor_time_counter++;
        if(armor_time_counter == 2){
          prev_state = STATE_READY_CH; // 擬似的に状態変化を起こす
          state = STATE_CHANGED;
          side  = SIDE_ARMOR_TIME;
        }
      }else if(prev_state == STATE_READY_CR){
        armor_time_counter++;
        if(armor_time_counter == 2){
          state = STATE_CRITICAL;
          side  = SIDE_ARMOR_TIME;
        }
      }
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON || prev_state == STATE_CHANGED || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, ON_ON_ON,    N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_OFF,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_OFF,   N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, ON_ON_OFF,  N_BUTTON) == 0){
    if(memcmp(sw, OFF_ON_OFF, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED || prev_state == STATE_READY_WP || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, ON_ON_ON,    N_BUTTON) == 0){
      if(prev_state == STATE_READY_WP){
        state = STATE_WEAPON;
      }else if(prev_state == STATE_READY_CH || prev_state == STATE_CHANGED){
        rider_time_counter++;
        if(rider_time_counter == 2){
          prev_state = STATE_READY_CH; // 擬似的に状態変化を起こす
          state = STATE_CHANGED;
          side  = SIDE_RIDER_TIME;
        }
      }else if(prev_state == STATE_READY_CR){
        rider_time_counter++;
        if(rider_time_counter == 2){
          state = STATE_CRITICAL;
          side  = SIDE_RIDER_TIME;
        }
      }
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_ON,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_ON,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_OFF_ON,  N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, ON_OFF_ON,  N_BUTTON) == 0){
    if(memcmp(sw, OFF_OFF_ON, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_ON,    N_BUTTON) == 0){
      if(prev_state == STATE_SINGLE_A || prev_state == STATE_SINGLE_B){
        state = STATE_READY_CH;
      }else if(prev_state == STATE_READY_CH || prev_state == STATE_CHANGED){
        armor_time_counter++;
        if(armor_time_counter == 2){
          prev_state = STATE_READY_CH; // 擬似的に状態変化を起こす
          state = STATE_CHANGED;
          side  = SIDE_ARMOR_TIME;
        }
      }else if(prev_state == STATE_READY_CR){
        armor_time_counter++;
        if(armor_time_counter == 2){
          state = STATE_CRITICAL;
          side  = SIDE_ARMOR_TIME;
        }
      }
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON || prev_state == STATE_CHANGED || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, OFF_ON_ON,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_OFF,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_OFF,  N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, OFF_ON_ON,  N_BUTTON) == 0){
    if(memcmp(sw, ON_ON_ON, N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED){
        reset_all();
        state = STATE_READY_CR;
      }else if(prev_state == STATE_READY_CR || prev_state == STATE_CRITICAL){
        reset_all();
        prev_state = STATE_CHANGED; // 擬似的に状態変化を起こす
        state = STATE_READY_CR;
      }
    }else if(memcmp(sw, OFF_OFF_ON,  N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED){
        side = SIDE_NONE;
        if(armor_time_counter == 2){
          reset_armor_time_counter();
        }
      }else if(prev_state == STATE_CRITICAL){
        state = STATE_CHANGED;
        side  = SIDE_NONE;
        if(armor_time_counter == 2){
          reset_armor_time_counter();
        }
      }
    }else if(memcmp(sw, OFF_ON_OFF,  N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON){
        state = STATE_READY_WP;
      }else if(prev_state == STATE_CHANGED){
        side = SIDE_NONE;
        if(rider_time_counter == 2){
          reset_rider_time_counter();
        }
      }else if(prev_state == STATE_CRITICAL){
        state = STATE_CHANGED;
        side  = SIDE_NONE;
        if(rider_time_counter == 2){
          reset_rider_time_counter();
        }
      }
    }else if(memcmp(sw, ON_OFF_ON,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_ON_OFF,   N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON || prev_state == STATE_CHANGED || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR || prev_state == STATE_CRITICAL){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      ;
    }
  }else if(memcmp(prev_sw, ON_ON_ON,   N_BUTTON) == 0){
    if(memcmp(sw, OFF_ON_ON, N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_ON,   N_BUTTON) == 0){
      if(prev_state == STATE_CHANGED){
        side = SIDE_NONE;
        if(armor_time_counter == 2){
          reset_armor_time_counter();
        }
      }else if(prev_state == STATE_CRITICAL){
        state = STATE_CHANGED;
        side  = SIDE_NONE;
        if(armor_time_counter == 2){
          reset_armor_time_counter();
        }
      }
    }else if(memcmp(sw, ON_ON_OFF,   N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON){
        state = STATE_READY_WP;
      }else if(prev_state == STATE_CHANGED){
        side = SIDE_NONE;
        if(rider_time_counter == 2){
          reset_rider_time_counter();
        }
      }else if(prev_state == STATE_CRITICAL){
        state = STATE_CHANGED;
        side  = SIDE_NONE;
        if(rider_time_counter == 2){
          reset_rider_time_counter();
        }
      }
    }else if(memcmp(sw, OFF_OFF_ON,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, OFF_ON_OFF,  N_BUTTON) == 0){
      ;
    }else if(memcmp(sw, ON_OFF_OFF,  N_BUTTON) == 0){
      if(prev_state == STATE_WEAPON || prev_state == STATE_CHANGED || prev_state == STATE_READY_CH || prev_state == STATE_READY_CR || prev_state == STATE_CRITICAL){
        reset_all();
        state = STATE_SINGLE_A;
      }
    }else if(memcmp(sw, OFF_OFF_OFF, N_BUTTON) == 0){
      ;
    }
  }

  /*
  Serial.print("State: ");
  Serial.println(state);
  Serial.print("rider time counter: ");
  Serial.println(rider_time_counter);
  Serial.print("armor time counter: ");
  Serial.println(armor_time_counter);
  Serial.println("");
  Serial.println(digitalRead(REED_PIN));
  */ 

  play_sound();
  flash_led();

  prev_sw[0] = sw[0];
  prev_sw[1] = sw[1];
  prev_sw[2] = sw[2];

  // ---------- フォームチェンジ処理 ----------
  relay = digitalRead(REED_PIN);
  if(prev_relay != relay){
    form_change_counter++;
    if(form_change_counter == 2){
      switch(form_state){
      case FORM_STATE_CROSS_Z:
        form_state = FORM_STATE_CHARGE;
        mp3_player.playMp3Folder(SOUND_CHANGE_CHARGE);
        for(uint16_t i=0;i<250;i++){
          led_pattern_change_charge(i*LOOP_INTERVAL_MS);
          pixels.show();
          delay(LOOP_INTERVAL_MS);
        }
        break;
      case FORM_STATE_CHARGE:
        form_state = FORM_STATE_MAGMA;
        mp3_player.playMp3Folder(SOUND_CHANGE_MAGMA);
        for(uint16_t i=0;i<200;i++){
          led_pattern_change_magma(i*LOOP_INTERVAL_MS);
          pixels.show();
          delay(LOOP_INTERVAL_MS);
        }
        break;
      case FORM_STATE_MAGMA:
        form_state = FORM_STATE_CROSS_Z;
        mp3_player.playMp3Folder(SOUND_CHANGE_CROSS_Z);
        for(uint16_t i=0;i<100;i++){
          led_pattern_change_cross_z(i*LOOP_INTERVAL_MS);
          pixels.show();
          delay(LOOP_INTERVAL_MS);
        }
        break;
      default:
        ;
      }
      if(state == STATE_SINGLE_A || state == STATE_SINGLE_B){
        // ドライバーに装填していない状態でフォームチェンジしたときは、初期状態に戻す
        prev_state = state = STATE_SINGLE_A;
        reset_all();
      }
      form_change_counter = 0;
    }
  }
  prev_relay = relay;

  delay(LOOP_INTERVAL_MS);
}