/**********************************************************
   ASCII 8N2 50baud RTTY(T) v1.00 2016.11.30
/**********************************************************/

#include <LiquidCrystal.h>
#include <TimerOne.h>
#include <FlexiTimer2.h>
#include <PS2Keyboard.h>

LiquidCrystal lcd(4,5,6,7,8,9,10);

/*
#define MARK  294   // 294 = (500000 / 1700 Hz)
#define SPACE 392   // 392 = (500000 / 1275 Hz)
*/

#define MARK  346   // 346 = (500000 / 1445 Hz)
#define SPACE 392   // 392 = (500000 / 1275 Hz)


PS2Keyboard keyboard;
const int DataPin = 2;  //PS/2 DATA
const int IRQpin  = 3;  //PS/2 CLOCK

boolean  snd;
boolean  org;
int      ti;
int      x;
byte     y;
char     ch;
char     c[33];

void setup()
{
        Serial.begin(9600);
        lcd.begin(16, 2);
        lcd.cursor();
        lcd.setCursor(0, 0);
        keyboard.begin(DataPin, IRQpin);
        pinMode(12, OUTPUT);  //--AFSK AUDIO OUTPUT
        pinMode(13, OUTPUT);  //--TTL LEVEL OUTPUT
        digitalWrite(13, 1);
        
        Timer1.initialize();
        Timer1.attachInterrupt(timer1_interrupt, MARK);
        
        FlexiTimer2::set(1, timer2_interrupt);
        FlexiTimer2::start();
}

//AFSK TONE GENERATOR
void timer1_interrupt(void)
{
        static boolean toggle;
        
        toggle = toggle ^ 1;
        digitalWrite(12, toggle);
}

//8BIT ASCII GENERATOR
void timer2_interrupt(void)
{
        static boolean bit1;
        static boolean bit2;
        static boolean bit3;
        static boolean bit4;
        static boolean bit5;
        static boolean bit6;
        static boolean bit7;
        static boolean bit8;
        
        if(snd == 1)
        {
                switch(ti)
                {
                        case 0:
                                digitalWrite(13, 0);
                                Timer1.setPeriod(SPACE);
                                
                                bit1 = ch & B00000001;
                                bit2 = ch & B00000010;
                                bit3 = ch & B00000100;
                                bit4 = ch & B00001000;
                                bit5 = ch & B00010000;
                                bit6 = ch & B00100000;
                                bit7 = ch & B01000000;
                                bit8 = ch & B10000000;
                                break;
                        case 20:
                                digitalWrite(13, bit1);
                                if(bit1){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 40:
                                digitalWrite(13, bit2);
                                if(bit2){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 60:
                                digitalWrite(13, bit3);
                                if(bit3){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 80:
                                digitalWrite(13, bit4);
                                if(bit4){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 100:
                                digitalWrite(13, bit5);
                                if(bit5){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 120:
                                digitalWrite(13, bit6);
                                if(bit6){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 140:
                                digitalWrite(13, bit7);
                                if(bit7){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 160:
                                digitalWrite(13, bit8);
                                if(bit8){Timer1.setPeriod(MARK);}
                                    else{Timer1.setPeriod(SPACE);}
                                break;
                        case 180:
                                digitalWrite(13, 1);
                                Timer1.setPeriod(MARK);
                                break;
                        case 220:
                                snd = 0;
                                break;
                }
                ti++;
        }
}

//DISPLAYS CHARACTER
void lcdOut()
{
        int i;
        
        lcd.print(ch);
        c[16 * y + x] = ch;
        x++;
        if(x == 16 && y == 0)
        {
                x = 0; y = 1;
        }  
        else if(x == 16 && y == 1)
        {
                for(i = 0; i < 16; i++)
                {
                        c[i] = c[16 + i];
                }
                for(i = 0; i < 16; i++)
                {
                        c[16 + i] = '\0';
                }
                lcd.clear();
                lcd.noCursor();
                for(i = 0; i < 16; i++)
                {
                        lcd.print(c[i]);
                }
                lcd.cursor();
                x = 0; y = 1;
        }
        lcd.setCursor(x, y);
}

//HANDLES BACKSPACE
void lcdBs()
{
        int i;
        
        if(x == 0 && y == 0)
        {
                org = true;
        }
        else
        {
                org = false;
                x--;
                if(x == -1 && y == 1)
                {
                        x = 15; y = 0;
                        while(c[x] == '\0')
                        {
                                x--;
                        }
                        lcd.noCursor();
                        lcd.setCursor(x, y);
                        lcd.print(" ");
                        lcd.setCursor(x, y);
                        lcd.cursor();
                        c[x] = '\0';
                }
                else
                {
                        lcd.noCursor();
                        lcd.setCursor(x, y);
                        lcd.print(" ");
                        lcd.setCursor(x, y);
                        lcd.cursor();
                        c[16 * y + x] = '\0';
                }
        }
}

//HANDLES CRLF
void lcdCrLf()
{
        byte skip = (16 - x);
        int i;
        
        lcd.noCursor();
        for(i = 0; i < skip; i++)
        {
                if(i == 0)
                {
                        c[16 * y + x] = '\r';
                }
                else
                {
                        c[16 * y + x] = '\0';
                }
                x++;
        }
        if(y == 0)
        {
                x = 0; y = 1;
        }
        else
        {
                for(i = 0; i < 16; i++)
                {
                        c[i] = c[16 + i];
                }
                for(i = 0; i < 16; i++)
                {
                        c[16 + i] = '\0';
                }
                lcd.clear();
                for(i = 0; i < 16; i++)
                {
                        if(c[i] == '\r' || c[i] == '\0')
                        {
                                lcd.print(' ');
                        }
                        else
                        {
                                lcd.print(c[i]);
                        }
                }
                x = 0; y = 1;
        }
        lcd.setCursor(x, y);
        lcd.cursor();
}

void chIgnore()
{
             if(ch == PS2_TAB       ){ch = '\0';} //IGNORE THESE KEYS
        else if(ch == PS2_ESC       ){ch = '\0';}
        else if(ch == PS2_PAGEUP    ){ch = '\0';}
        else if(ch == PS2_PAGEDOWN  ){ch = '\0';}
        else if(ch == PS2_UPARROW   ){ch = '\0';}
        else if(ch == PS2_LEFTARROW ){ch = '\0';}
        else if(ch == PS2_DOWNARROW ){ch = '\0';}
        else if(ch == PS2_RIGHTARROW){ch = '\0';}
}

void loop()
{
        static boolean crLf;
        
        if(snd == 0)
        {
                if(crLf == 1)
                {
                        crLf = 0;
                        lcdCrLf();
                        ch = '\n';
                        ti = 0; snd = 1; //2nd byte
                }
                else if (keyboard.available())
                {
                        ch = keyboard.read();
                        chIgnore();
                        if(ch != '\0')
                        {
                                if(ch == PS2_BACKSPACE || ch == PS2_DELETE)
                                {
                                        lcdBs();
                                        if(org == false)
                                        {
                                                ch = 0x08; //BS
                                                ti = 0; snd = 1; //1st byte
                                        }
                                }
                                else if(ch == '\r')
                                {
                                        crLf = 1;
                                        ti = 0; snd = 1; //1st byte
                                }
                                else
                                {
                                        lcdOut();
                                        ti = 0; snd = 1; //1st byte
                                }
                        }
                }
        }
        delay(5);
}