/*
MORSE DECODER Ver2
2016.7.9 JH7UBC
*/

#include <LiquidCrystal.h>

LiquidCrystal lcd(5,7,9,10,11,12);//  LiquidCrystal lcd(RS, E, D4, D5, D6, D7)
const int colums = 20; /// have to be 16 or 20
const int rows = 4;  /// have to be 2 or 4
int lcdindex = 0;
int line1[colums];
int line2[colums];

const int Input_Pin = 2;//信号入力
const int SW = 3;//欧文/和文切り替えSW
const int LED = 4;//和文モード表示LED
int val = 1;//SWの値、初期値1
int old_val = 1;//valの値の前の状態
byte X = 1;//内部コード初期値(スタートビット)
byte F = 1;//スペース表示済みのフラッグ、初期値1
byte WabunF = 0;//和文フラッグ、初期値0=欧文

unsigned long T=100;//dotとdashを区別する値の初期値T=dot*2
unsigned long A=0;//1から0に変化した時刻 ms
unsigned long B=0;//0から1に変化した時刻 ms
unsigned long D;//0が継続した時間 ms D=B-A
unsigned long C;//1を検出した時刻 ms
unsigned long E;//1が継続している時間 ms E=C-B
unsigned long W;//W=dot*5
char AsciiCode[128];//欧文
char WabunCode[256];//和文

void setup(){
  pinMode(Input_Pin,INPUT);
  digitalWrite(Input_Pin,HIGH);//入力ピンをプルアップ
  pinMode(SW,INPUT);
  digitalWrite(SW,HIGH);//SWピンをプルアップ
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  lcd.begin(colums, rows); 
   for (int index = 0; index < colums; index++){
    line1[index] = 32;//line1にスペースを書き込む
    line2[index] = 32;//line2にスペースを書き込む
 }           
  lcd.print("MORSE DECODER Ver2.0");
  for (int i=0;i<128;i++){
    AsciiCode[i]=32;
  }
  for (int i=0;i<256;i++){
    WabunCode[i]=32;
  }
  Code_Set();//配列にアスキーコードを格納する。
}

void loop(){
  ModeChange();
  if(digitalRead(Input_Pin) == 0){
    A=millis();
    do{
    }while(digitalRead(Input_Pin) == 0);//入力が0の間ループ
    B=millis();
    D=B-A;
    if (D < T){//短点の場合
      X=X<<1;//Xを左に1ビットシフト
      T=D<<1;//T=D*2
      W=D*5;
    }else{//長点の場合
      X=X<<1;
      X=X|1;
    }
  }else{
    C=millis();
    E=C-B;
    if ((E > T) && (X != 1)){
      switch (X){
       case 103://"ホレ"を受信した場合
          WabunF=1;//和文フラッグを立てる
          printascii(60);//"<"を表示
       break;

       case 34://"ラタ"を受信した場合
         WabunF=0;//和文フラッグを下す
         printascii(62);//">"を表示
       break;

       case 109://和文モード中に"("を受信した場合
         if (WabunF ==1 ){
           WabunF=0;
           printascii(40);
         }
        break;

       case 82://
        if (WabunF == 0){
          WabunF=1;
          printascii(41);
        }     
        break;
 
        default://それ以外の場合
          if (WabunF == 0){
            printascii(AsciiCode[X]);//欧文表示
            }else{
            printascii(WabunCode[X]);//和文表示
            }
      }
      X=1;
      F=0;
    }else{
      if((E > W) && (F == 0)){
        printascii(32);    
        F=1;
      }
    }
  }
}

void ModeChange(){
  val = digitalRead(SW);
  if (val == LOW && old_val == HIGH){
    WabunF = 1 - WabunF;
    delay(10);
  }
  old_val = val;
  if (WabunF == 1){
    digitalWrite(LED,HIGH);//LED点灯
  }else{
    digitalWrite(LED,LOW);//LED消灯
  }
}

void Code_Set(){
    AsciiCode[5]='A';
    AsciiCode[24]='B';
    AsciiCode[26]='C';
    AsciiCode[12]='D';
    AsciiCode[2]='E';
    AsciiCode[18]='F';
    AsciiCode[14]='G';
    AsciiCode[16]='H';
    AsciiCode[4]='I';
    AsciiCode[23]='J';
    AsciiCode[13]='K';
    AsciiCode[20]='L';
    AsciiCode[7]='M';
    AsciiCode[6]='N';
    AsciiCode[15]='O';
    AsciiCode[22]='P';
    AsciiCode[29]='Q';
    AsciiCode[10]='R';
    AsciiCode[8]='S';
    AsciiCode[3]='T';
    AsciiCode[9]='U';
    AsciiCode[17]='V';
    AsciiCode[11]='W';
    AsciiCode[25]='X';
    AsciiCode[27]='Y';
    AsciiCode[28]='Z';
    AsciiCode[47]='1';
    AsciiCode[39]='2';
    AsciiCode[35]='3';
    AsciiCode[33]='4';
    AsciiCode[32]='5';
    AsciiCode[48]='6';
    AsciiCode[56]='7';
    AsciiCode[60]='8';
    AsciiCode[62]='9';
    AsciiCode[63]='0';
    AsciiCode[50]='/';
    AsciiCode[76]='?';
    AsciiCode[115]=',';
    AsciiCode[85]='.';
    AsciiCode[90]='@';
    WabunCode[59]=177;//ア
    WabunCode[5]=178;//イ
    WabunCode[9]=179;//ウ
    WabunCode[55]=180;//エ
    WabunCode[40]=181;//オ
    WabunCode[20]=182;//カ
    WabunCode[52]=183;//キ
    WabunCode[17]=184;//ク
    WabunCode[27]=185;//ケ
    WabunCode[31]=186;//コ
    WabunCode[53]=187;//サ
    WabunCode[58]=188;//シ
    WabunCode[61]=189;//ス
    WabunCode[46]=190;//セ
    WabunCode[30]=191;//ソ
    WabunCode[6]=192;//タ
    WabunCode[18]=193;//チ
    WabunCode[22]=194;//ツ
    WabunCode[43]=195;//テ
    WabunCode[36]=196;//ト
    WabunCode[10]=197;//ナ
    WabunCode[26]=198;//ニ
    WabunCode[16]=199;//ヌ
    WabunCode[29]=200;//ネ
    WabunCode[19]=201;//ノ
    WabunCode[24]=202;//ハ
    WabunCode[57]=203;//ヒ
    WabunCode[28]=204;//フ
    WabunCode[2]=205;//ヘ
    WabunCode[12]=206;//ホ
    WabunCode[25]=207;//マ
    WabunCode[37]=208;//ミ
    WabunCode[3]=209;//ム
    WabunCode[49]=210;//メ
    WabunCode[50]=211;//モ
    WabunCode[11]=212;//ヤ
    WabunCode[51]=213;//ユ
    WabunCode[7]=214;//ヨ
    WabunCode[8]=215;//ラ
    WabunCode[14]=216;//リ
    WabunCode[54]=217;//ル
    WabunCode[15]=218;//レ
    WabunCode[21]=219;//ロ
    WabunCode[13]=220;//ワ
    WabunCode[23]=166;//ヲ
    WabunCode[42]=221;//ン
    WabunCode[4]=222;//゙
    WabunCode[38]=223;//゚
    WabunCode[45]=176;//ー
    WabunCode[109]='(';
    WabunCode[82]=')';
    WabunCode[63]='0';
    WabunCode[47]='1';
    WabunCode[39]='2';
    WabunCode[35]='3';
    WabunCode[33]='4';
    WabunCode[32]='5';
    WabunCode[48]='6';
    WabunCode[56]='7';
    WabunCode[60]='8';
    WabunCode[62]='9';
    WabunCode[76]='?';
    WabunCode[85]='.';
    WabunCode[115]=',';
}

void printascii(int asciinumber){

int fail = 0;
if (rows == 4 and colums == 16)fail = -4;

 if (lcdindex > colums-1){
  lcdindex = 0;
  if (rows==4){
	  for (int i = 0; i <= colums-1 ; i++){
		lcd.setCursor(i,rows-3);
		lcd.write(line2[i]);
		line2[i]=line1[i];
	  }
   }
  for (int i = 0; i <= colums-1 ; i++){
    lcd.setCursor(i+fail,rows-2);
    lcd.write(line1[i]);
	lcd.setCursor(i+fail,rows-1);
    lcd.write(32);
  }
 }
 line1[lcdindex]=asciinumber;
 lcd.setCursor(lcdindex+fail,rows-1);
 lcd.write(asciinumber);
 lcdindex += 1;
}