////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// JI3BNB RTTY ENCODER for ARDUINO UNO - 20CH MEMORY VERSION -
// 2018.03.20 v7.0
//
// DESIGNED FOR AMATEUR RADIO COMMUNICATION
// - REALTIME KEYBOARD INPUT
// - 5BIT BAUDOT CODE, 45.45baud
// - EDIT MEMORY VIA PS/2 KEYBOARD
// - LCD 16x2 (SC1602BBWB-XA-GB-G) or 20x4 (UC-204)
//
// SCHEMATIC http://k183.bake-neko.net/ji3bnb/page13.html
// ** THIS PROGRAM IS IN THE PUBLIC DOMAIN **-
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- BASIC SET UP AND PIN ASSIGNMENTS --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
#include <TimerOne.h>
// ** REQUIRE "TimerOne" LIBRARY **
// http://playground.arduino.cc/code/timer1
#define MARK 392 // 392 = (500000 / 1275 Hz)
#define SPACE 346 // 346 = (500000 / 1445 Hz)
// #define MARK 346 // 346 = (500000 / 1445 Hz)
// #define SPACE 392 // 392 = (500000 / 1275 Hz)
// #define MARK 218 // 235 = (500000 / 2125 Hz)
// #define SPACE 235 // 218 = (500000 / 2295 Hz)
// #define MARK 235 // 218 = (500000 / 2295 Hz)
// #define SPACE 218 // 235 = (500000 / 2125 Hz)
////////////////////////////////////////////////////////////////////////////////
#include <FlexiTimer2.h>
// ** REQUIRE "FlexiTimer2" LIBRARY **
// http://playground.arduino.cc/Main/FlexiTimer2
////////////////////////////////////////////////////////////////////////////////
#include <PS2Keyboard.h>
// ** REQUIRE "PS2Keyboard" LIBRARY **
// http://playground.arduino.cc/Main/PS2Keyboard
PS2Keyboard keyboard;
const int DataPin = 2; //D2 = "DATA" PIN
const int IRQpin = 3; //D3 = "CLOCK" PIN (!!DO NOT CAHNGE THIS)
const byte jp106 = 0;
// SELECT 0: ENGLISH KEYBOARD
// SELECT 1: JAPANESE KEYBOARD 日本語キーボード
////////////////////////////////////////////////////////////////////////////////
#include <LiquidCrystal.h>
// LCD DISPLAY (HITACHI HD44780 INTERFACE)
const boolean lcdType = 1;
// SELECT 0: 16x2
// SELECT 1: 20x4
LiquidCrystal lcd(4,5,6,7,8,9,10);
// ARDUINO D10 -> LCD D7
// ARDUINO D9 -> LCD D6
// ARDUINO D8 -> LCD D5
// ARDUINO D7 -> LCD D4
// ARDUINO D6 -> LCD EN
// ARDUINO D5 -> LCD R/W
// ARDUINO D4 -> LCD RS
////////////////////////////////////////////////////////////////////////////////
// 20CH MEMORY '1'-'0','F1'-'F10' KEYS
#include <EEPROM.h>
// ADDRESS TABLE
const int addrTb[] = {2,35,68,101,134,167,200,233,266,299,-1,332,365,398,431,464,545,626,659,692};
// NUMBER KEY '1'-'0'
char n01[33]; //00 * MAX 32 CHARACTERS (INCLUDING CR & SPACE)
char n02[33]; //01 *
char n03[33]; //02 *
char n04[33]; //03 *
char n05[33]; //04 *
char n06[33]; //05 *
char n07[33]; //06 *
char n08[33]; //07 *
char n09[33]; //08 *
char n00[33]; //09 *
// FUNCTION KEY 'F1'-'F10'
char f01[17]; //10 * MAX 16 CHARACTERS -- HIS/HER CALLSIGN -- (!! NOT SAVED TO EEPROM !!)
char f02[33]; //11 *
char f03[33]; //12 *
char f04[33]; //13 *
char f05[33]; //14 *
char f06[81]; //15 * MAX 80 CHARACTERS (INCLUDING CR & SPACE)
char f07[81]; //16 * MAX 80 CHARACTERS (INCLUDING CR & SPACE)
char f08[33]; //17 *
char f09[33]; //18 *
char f10[33]; //19 *
// ALERTS
char a01[] = "EMPTY!"; //20
char a02[] = "OVERWRITE?"; //21
char a03[] = "SAVED!"; //22
// ARRAY
char* ms[] = {n00,n01,n02,n03,n04,n05,n06,n07,n08,n09,f01,f02,f03,f04,f05,f06,f07,f08,f09,f10,a01,a02,a03};
////////////////////////////////////////////////////////////////////////////////
// D12 : ENCODER OUTPUT (AFSK AUDIO)
////////////////////////////////////////////////////////////////////////////////
// D13 : ENCODER OUTPUT (0/5V TTL LEVEL)
////////////////////////////////////////////////////////////////////////////////
// A0(=D14) : ESC INDICATOR
// THIS INDICATOR MEANS "NOW IN 20CH MEMORY MODE"
// WHEN FLASHING, IT MEANS "EDIT MODE ACTIVE"
////////////////////////////////////////////////////////////////////////////////
// A1(=D15) : TX INDICATOR
// ALSO PTT CONTROL VOLTAGE
////////////////////////////////////////////////////////////////////////////////
// A4(=D18) : TX SW
// CONNECT TO GND WHEN TX
////////////////////////////////////////////////////////////////////////////////
// "BAUDOT" CODE HAS SOME TYPES OF VARIATION
const boolean usFig = 1;
// SELECT 0: "TONO THETA-5000E" COMPATIBLE (ALSO "MixW" COMPATIBLE)
// SELECT 1: "Fldigi" COMPATIBLE (=USTTY, POPULARLY USED)
////////////////////////////////////////////////////////////////////////////////
// DIDDLE ENABLE AND INTERVAL PERIOD
const boolean ddl = 1; //ENABLE
const int ddItv = 260; //INTERVAL (ms)
////////////////////////////////////////////////////////////////////////////////
// SPECIAL KEYS
// [Esc] : GO INTO OR GO OUT OF "20CH MEMORY MODE"
// [DOWN ARROW] : SAVE CHANGES
// [RIGHT ARROW] : SKIP PLAYBACK
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- GLOBAL VARIABLES, FLAGS, COUNTERS etc --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
boolean space;
boolean shift;
boolean crLf;
boolean fig_1;
int fig_2;
int x; //CURSOR POSITION
byte y; //CURSOR POSITION
char c[81]; //DISPLAY BUFFER
char keyBuf[5]; //KEY BUFFER
char ch;
volatile boolean empCh;
volatile boolean snd;
volatile boolean f1Stord;
volatile int ti;
volatile int ddCnt;
volatile int flshCnt;
volatile byte tRx;
volatile byte tRL;
volatile byte eSq;
uint8_t baudot;
uint8_t baudot_;
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- setup() --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
void setup()
{
Serial.begin(9600);
if(lcdType == 0){lcd.begin(16, 2);}
else if(lcdType == 1){lcd.begin(20, 4);}
lcd.cursor();
lcd.setCursor(0, 0);
keyboard.begin(DataPin, IRQpin);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
digitalWrite(13, 1);
digitalWrite(18, 1); //INTERNAL PULL UP
Timer1.initialize();
FlexiTimer2::set(1, timer2_interrupt);
FlexiTimer2::start();
//RESTORE MEMORIES WHEN START UP
if(EEPROM.read(0) != 'N' || EEPROM.read(1) != 'N') //CLEAN UP
{
EEPROM.write(0, 'N');
EEPROM.write(1, 'N');
for(int i = 2; i < 1024; i++)
{
EEPROM.write(i, '\0');
}
}
for(int msNo = 0; msNo < 20; msNo++)
{
int startAddr = addrTb[msNo];
if(msNo == 10)
{
//SKIP
}
else if(msNo == 15 || msNo == 16)
{
Serial.println(startAddr);
for(int m = 0; m < 80; m++)
{
ms[msNo][m] = EEPROM.read(startAddr + m);
}
Serial.println("RESTORED");
}
else
{
Serial.println(startAddr);
for(int m = 0; m < 32; m++)
{
ms[msNo][m] = EEPROM.read(startAddr + m);
}
Serial.println("RESTORED");
}
}
}
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- timer_interrupt --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
//AFSK TONE GENERATOR
void timer1_interrupt(void)
{
static boolean toggle;
toggle = toggle ^ 1;
digitalWrite(12, toggle);
}
//5BIT BAUDOT GENERATOR
void timer2_interrupt(void)
{
static boolean bit1;
static boolean bit2;
static boolean bit3;
static boolean bit4;
static boolean bit5;
if(tRx == 0 && digitalRead(18) == 0)
{
tRx = 1;
tRL = 1;
}
else if(tRx == 1 || tRx == 2)
{
if(ddCnt < 2000)
{
ddCnt++;
}
if(snd == 1)
{
switch(ti)
{
case 0:
ddCnt = 0;
digitalWrite(13, 0);
Timer1.setPeriod(SPACE);
bit1 = baudot & B00001;
bit2 = baudot & B00010;
bit3 = baudot & B00100;
bit4 = baudot & B01000;
bit5 = baudot & B10000;
break;
case 22:
digitalWrite(13, bit1);
if(bit1){Timer1.setPeriod(MARK);}
else{Timer1.setPeriod(SPACE);}
break;
case 44:
digitalWrite(13, bit2);
if(bit2){Timer1.setPeriod(MARK);}
else{Timer1.setPeriod(SPACE);}
break;
case 66:
digitalWrite(13, bit3);
if(bit3){Timer1.setPeriod(MARK);}
else{Timer1.setPeriod(SPACE);}
break;
case 88:
digitalWrite(13, bit4);
if(bit4){Timer1.setPeriod(MARK);}
else{Timer1.setPeriod(SPACE);}
break;
case 110:
digitalWrite(13, bit5);
if(bit5){Timer1.setPeriod(MARK);}
else{Timer1.setPeriod(SPACE);}
break;
case 132:
digitalWrite(13, 1);
Timer1.setPeriod(MARK);
break;
case 165:
snd = 0;
break;
}
ti++;
}
}
if(tRx == 0 && eSq >= 2)
{
if(flshCnt == 250)
{
digitalWrite(14, 1);
}
else if(flshCnt == 500)
{
digitalWrite(14, 0);
flshCnt = 0;
}
flshCnt++;
}
else if(f1Stord == true)
{
switch(flshCnt)
{
case 150:
digitalWrite(14, 0);
break;
case 300:
digitalWrite(14, 1);
break;
case 450:
digitalWrite(14, 0);
f1Stord = false;
break;
}
flshCnt++;
}
else if(empCh == true)
{
if(flshCnt == 230)
{
digitalWrite(14, 0);
empCh = false;
}
flshCnt++;
}
}
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- OTHER FUNCTIONS etc --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
//DISPLAY CHARACTER
void lcdChOut()
{
int i;
if(lcdType == 0) //16x2
{
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);
}
else if(lcdType == 1) //20x4
{
lcd.print(ch);
c[20 * y + x] = ch;
x++;
if(x == 20 && y <= 2)
{
x = 0; y++;
}
else if(x == 20 && y == 3)
{
for(i = 0; i < 60; i++)
{
c[i] = c[20 + i];
}
for(i = 0; i < 20; i++)
{
c[60 + i] = '\0';
}
lcd.clear();
lcd.noCursor();
for(y = 0; y < 3; y++)
{
lcd.setCursor(0, y);
for(i = 0; i < 20; i++)
{
if(c[20 * y + i] == '\r' || c[20 * y + i] == '\0')
{
lcd.print(' ');
}
else
{
lcd.print(c[20 * y + i]);
}
}
}
lcd.cursor();
x = 0; y = 3;
}
lcd.setCursor(x, y);
}
}
//HANDLES BACKSPACE
void lcdBs()
{
int i;
if(lcdType == 0) //16x2
{
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[16 * y + x] = '\0';
}
else if(lcdType == 1) //20x4
{
x--;
if(x == -1 && y >= 1)
{
x = 19; y--;
while(c[20 * y + x] == '\0')
{
x--;
}
}
lcd.noCursor();
lcd.setCursor(x, y);
lcd.print(" ");
lcd.setCursor(x, y);
lcd.cursor();
c[20 * y + x] = '\0';
}
}
//HANDLES CRLF
void lcdCrLf()
{
int i;
if(lcdType == 0) //16x2
{
byte skip = (16 - x);
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();
}
else if(lcdType == 1) //20x4
{
byte skip = (20 - x);
lcd.noCursor();
for(i = 0; i < skip; i++)
{
if(i == 0)
{
c[20 * y + x] = '\r';
}
else
{
c[20 * y + x] = '\0';
}
x++;
}
if(y <= 2)
{
x = 0; y++;
}
else if(y == 3)
{
for(i = 0; i < 60; i++)
{
c[i] = c[20 + i];
}
for(i = 0; i < 20; i++)
{
c[60 + i] = '\0';
}
lcd.clear();
for(y = 0; y < 3; y++)
{
lcd.setCursor(0, y);
for(i = 0; i < 20; i++)
{
if(c[20 * y + i] == '\r' || c[20 * y + i] == '\0')
{
lcd.print(' ');
}
else
{
lcd.print(c[20 * y + i]);
}
}
}
x = 0; y = 3;
}
lcd.setCursor(x, y);
lcd.cursor();
}
}
//LOOK UP TABLE
void chTableT()
{
if(usFig == 1) //"Fldigi" COMPATIBLE
{
fig_2 = -1;
switch(ch){
case 'A': baudot = B00011; fig_2 = 0; break;
case 'B': baudot = B11001; fig_2 = 0; break;
case 'C': baudot = B01110; fig_2 = 0; break;
case 'D': baudot = B01001; fig_2 = 0; break;
case 'E': baudot = B00001; fig_2 = 0; break;
case 'F': baudot = B01101; fig_2 = 0; break;
case 'G': baudot = B11010; fig_2 = 0; break;
case 'H': baudot = B10100; fig_2 = 0; break;
case 'I': baudot = B00110; fig_2 = 0; break;
case 'J': baudot = B01011; fig_2 = 0; break;
case 'K': baudot = B01111; fig_2 = 0; break;
case 'L': baudot = B10010; fig_2 = 0; break;
case 'M': baudot = B11100; fig_2 = 0; break;
case 'N': baudot = B01100; fig_2 = 0; break;
case 'O': baudot = B11000; fig_2 = 0; break;
case 'P': baudot = B10110; fig_2 = 0; break;
case 'Q': baudot = B10111; fig_2 = 0; break;
case 'R': baudot = B01010; fig_2 = 0; break;
case 'S': baudot = B00101; fig_2 = 0; break;
case 'T': baudot = B10000; fig_2 = 0; break;
case 'U': baudot = B00111; fig_2 = 0; break;
case 'V': baudot = B11110; fig_2 = 0; break;
case 'W': baudot = B10011; fig_2 = 0; break;
case 'X': baudot = B11101; fig_2 = 0; break;
case 'Y': baudot = B10101; fig_2 = 0; break;
case 'Z': baudot = B10001; fig_2 = 0; break;
case '0': baudot = B10110; fig_2 = 1; break;
case '1': baudot = B10111; fig_2 = 1; break;
case '2': baudot = B10011; fig_2 = 1; break;
case '3': baudot = B00001; fig_2 = 1; break;
case '4': baudot = B01010; fig_2 = 1; break;
case '5': baudot = B10000; fig_2 = 1; break;
case '6': baudot = B10101; fig_2 = 1; break;
case '7': baudot = B00111; fig_2 = 1; break;
case '8': baudot = B00110; fig_2 = 1; break;
case '9': baudot = B11000; fig_2 = 1; break;
case '-': baudot = B00011; fig_2 = 1; break;
case '?': baudot = B11001; fig_2 = 1; break;
case ':': baudot = B01110; fig_2 = 1; break;
case '(': baudot = B01111; fig_2 = 1; break;
case ')': baudot = B10010; fig_2 = 1; break;
case '.': baudot = B11100; fig_2 = 1; break;
case ',': baudot = B01100; fig_2 = 1; break;
case '/': baudot = B11101; fig_2 = 1; break;
//"Fldigi" COMPATIBLE
case '$' : baudot = B01001; fig_2 = 1; break;
case '\'': baudot = B01011; fig_2 = 1; break;
case '!' : baudot = B01101; fig_2 = 1; break;
case '"' : baudot = B10001; fig_2 = 1; break;
case '#' : baudot = B10100; fig_2 = 1; break;
case '&' : baudot = B11010; fig_2 = 1; break;
case ';' : baudot = B11110; fig_2 = 1; break;
case '\r':
baudot = B01000; //CR
crLf = 1;
break;
case ' ':
baudot = B00100; //SPACE
space = 1;
break;
case PS2_ESC:
break;
case PS2_BACKSPACE:
break;
case PS2_DOWNARROW:
break;
case PS2_RIGHTARROW:
break;
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
break;
default:
ch = ' ';
baudot = B00100; //SPACE
space = 1;
break;
}
}
else if(usFig == 0) //"TONO THETA-5000E" COMPATIBLE
{
fig_2 = -1;
switch(ch){
case 'A': baudot = B00011; fig_2 = 0; break;
case 'B': baudot = B11001; fig_2 = 0; break;
case 'C': baudot = B01110; fig_2 = 0; break;
case 'D': baudot = B01001; fig_2 = 0; break;
case 'E': baudot = B00001; fig_2 = 0; break;
case 'F': baudot = B01101; fig_2 = 0; break;
case 'G': baudot = B11010; fig_2 = 0; break;
case 'H': baudot = B10100; fig_2 = 0; break;
case 'I': baudot = B00110; fig_2 = 0; break;
case 'J': baudot = B01011; fig_2 = 0; break;
case 'K': baudot = B01111; fig_2 = 0; break;
case 'L': baudot = B10010; fig_2 = 0; break;
case 'M': baudot = B11100; fig_2 = 0; break;
case 'N': baudot = B01100; fig_2 = 0; break;
case 'O': baudot = B11000; fig_2 = 0; break;
case 'P': baudot = B10110; fig_2 = 0; break;
case 'Q': baudot = B10111; fig_2 = 0; break;
case 'R': baudot = B01010; fig_2 = 0; break;
case 'S': baudot = B00101; fig_2 = 0; break;
case 'T': baudot = B10000; fig_2 = 0; break;
case 'U': baudot = B00111; fig_2 = 0; break;
case 'V': baudot = B11110; fig_2 = 0; break;
case 'W': baudot = B10011; fig_2 = 0; break;
case 'X': baudot = B11101; fig_2 = 0; break;
case 'Y': baudot = B10101; fig_2 = 0; break;
case 'Z': baudot = B10001; fig_2 = 0; break;
case '0': baudot = B10110; fig_2 = 1; break;
case '1': baudot = B10111; fig_2 = 1; break;
case '2': baudot = B10011; fig_2 = 1; break;
case '3': baudot = B00001; fig_2 = 1; break;
case '4': baudot = B01010; fig_2 = 1; break;
case '5': baudot = B10000; fig_2 = 1; break;
case '6': baudot = B10101; fig_2 = 1; break;
case '7': baudot = B00111; fig_2 = 1; break;
case '8': baudot = B00110; fig_2 = 1; break;
case '9': baudot = B11000; fig_2 = 1; break;
case '-': baudot = B00011; fig_2 = 1; break;
case '?': baudot = B11001; fig_2 = 1; break;
case ':': baudot = B01110; fig_2 = 1; break;
case '(': baudot = B01111; fig_2 = 1; break;
case ')': baudot = B10010; fig_2 = 1; break;
case '.': baudot = B11100; fig_2 = 1; break;
case ',': baudot = B01100; fig_2 = 1; break;
case '/': baudot = B11101; fig_2 = 1; break;
//"TONO THETA-5000E" COMPATIBLE
case '\'': baudot = B00101; fig_2 = 1; break;
case '$' : baudot = B01001; fig_2 = 1; break;
case '!' : baudot = B01101; fig_2 = 1; break;
case '+' : baudot = B10001; fig_2 = 1; break;
case '#' : baudot = B10100; fig_2 = 1; break;
case '&' : baudot = B11010; fig_2 = 1; break;
case '=' : baudot = B11110; fig_2 = 1; break;
case '\r':
baudot = B01000; //CR
crLf = 1;
break;
case ' ':
baudot = B00100; //SPACE
space = 1;
break;
case PS2_ESC:
break;
case PS2_BACKSPACE:
break;
case PS2_DOWNARROW:
break;
case PS2_RIGHTARROW:
break;
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
break;
default:
ch = ' ';
baudot = B00100; //SPACE
space = 1;
break;
}
}
}
void chConvt()
{
if(jp106 == 1) //JP106 KEYBOARD
{
switch(ch){
case '@' : ch = '"' ; break;
case '^' : ch = '&' ; break;
case '&' : ch = '\''; break;
case '*' : ch = '(' ; break;
case '(' : ch = ')' ; break;
case ')' : ch = '~' ; break;
case '_' : ch = '=' ; break;
case '=' : ch = '^' ; break;
case '+' : ch = '\0'; break;
case '[' : ch = '@' ; break;
case '{' : ch = '`' ; break;
case ']' : ch = '[' ; break;
case '}' : ch = '{' ; break;
case ':' : ch = '+' ; break;
case '\'': ch = ':' ; break;
case '"' : ch = '*' ; break;
case '\\': ch = ']' ; break;
case '|' : ch = '}' ; break;
}
}
if(usFig == 1) //"Fldigi" COMPATIBLE
{
if(ch >= 97 && ch <= 122) //CONVERT LOWER CASE TO UPPER CASE
{
ch = ch - 32;
}
else if(ch == PS2_TAB ){ch = '\0';} //IGNORE THESE KEYS
else if(ch == PS2_DELETE ){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 == 24 ){ch = '\0';}
else if(ch == 25 ){ch = '\0';}
else if(ch == '%' ){ch = '\0';}
else if(ch == '=' ){ch = '\0';}
else if(ch == '^' ){ch = '\0';}
else if(ch == '~' ){ch = '\0';}
else if(ch == '|' ){ch = '\0';}
else if(ch == '@' ){ch = '\0';}
else if(ch == '`' ){ch = '\0';}
else if(ch == '[' ){ch = '\0';}
else if(ch == '{' ){ch = '\0';}
else if(ch == '+' ){ch = '\0';}
else if(ch == '*' ){ch = '\0';}
else if(ch == ']' ){ch = '\0';}
else if(ch == '}' ){ch = '\0';}
else if(ch == '<' ){ch = '\0';}
else if(ch == '>' ){ch = '\0';}
else if(ch == '\\' ){ch = '\0';}
else if(ch == '_' ){ch = '\0';}
}
else if(usFig == 0) //"TONO THETA-5000E" COMPATIBLE
{
if(ch >= 97 && ch <= 122) //CONVERT LOWER CASE TO UPPER CASE
{
ch = ch - 32;
}
else if(ch == PS2_TAB ){ch = '\0';} //IGNORE THESE KEYS
else if(ch == PS2_DELETE ){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 == 24 ){ch = '\0';}
else if(ch == 25 ){ch = '\0';}
else if(ch == '"' ){ch = '\0';}
else if(ch == '%' ){ch = '\0';}
else if(ch == '^' ){ch = '\0';}
else if(ch == '~' ){ch = '\0';}
else if(ch == '|' ){ch = '\0';}
else if(ch == '@' ){ch = '\0';}
else if(ch == '`' ){ch = '\0';}
else if(ch == '[' ){ch = '\0';}
else if(ch == '{' ){ch = '\0';}
else if(ch == ';' ){ch = '\0';}
else if(ch == '*' ){ch = '\0';}
else if(ch == ']' ){ch = '\0';}
else if(ch == '}' ){ch = '\0';}
else if(ch == '<' ){ch = '\0';}
else if(ch == '>' ){ch = '\0';}
else if(ch == '\\' ){ch = '\0';}
else if(ch == '_' ){ch = '\0';}
}
}
void chFlush()
{
while(keyboard.available())
{
ch = keyboard.read();
}
for(int i = 0; i < 4; i++)
{
keyBuf[i] = '\0';
}
}
void chSend1()
{
if(fig_1 == 0 && fig_2 == 1) //SHIFT "UP"
{
baudot_ = baudot; //EVACUATE
baudot = B11011; //SEND FIGURE CODE FIRST
shift = 1;
}
else if(fig_1 == 1 && fig_2 == 0) //SHIFT "DOWN"
{
baudot_ = baudot; //EVACUATE
baudot = B11111; //SEND LETTER CODE FIRST
shift = 1;
}
else if(space == 1 && fig_2 == 1) //FIGURE AFTER SPACE (TX_UOS)
{
baudot_ = baudot; //EVACUATE
baudot = B11011; //SEND FIGURE CODE FIRST
shift = 1;
}
if(shift != 1 && crLf != 1)
{
lcdChOut();
}
if(fig_2 == 0 || fig_2 == 1)
{
space = 0;
fig_1 = fig_2; //REGISTER LAST STATE (EXCempCh SPACE, CR&LF)
}
ti = 0; snd = 1; //SEND(1)
}
void chSend2()
{
if(shift == 1) //2ND BYTE AFTER SENDING SHIFT CODE
{
baudot = baudot_; //RESTORE
lcdChOut();
shift = 0;
ti = 0; snd = 1; //SEND(2)
}
else if(crLf == 1) //2ND BYTE AFTER SENDING "CR"
{
baudot = B00010; //LF
lcdCrLf();
crLf = 0;
ti = 0; snd = 1; //SEND(2)
}
}
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// -- MAIN LOOP --
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
void loop()
{
static boolean esc;
static int msNo = -1;
static int msNo_;
static byte m;
static byte n;
static byte o;
static char mnBuf[8];
static char editBuf[81];
static char ch2;
if(tRx == 0) //RX
{
if(eSq > 0) //EDIT MODE
{
switch(eSq)
{
case 1: //PLAYBACK
ch = ms[msNo][m]; //READ MESSAGE
if(ch == '\0') //END OF MESSAGE
{
if(m == 0) //EMPTY
{
msNo_ = msNo;
msNo = 20;
}
else
{
if(msNo == 20)
{
msNo = msNo_;
}
if(x != 0)
{
lcdCrLf();
}
chFlush();
for(m = 0; m < 80; m++)
{
editBuf[m] = '\0';
}
m = 0;
flshCnt = 0;
digitalWrite(14, 0);
eSq = 2;
}
}
else
{
if(ch == '\r')
{
lcdCrLf();
}
else
{
lcdChOut();
}
delay(120); //--
m++;
}
if(keyboard.available())
{
ch2 = keyboard.read();
if(ch2 == PS2_RIGHTARROW) //SKIP
{
if(msNo == 20)
{
msNo = msNo_;
}
if(x != 0)
{
lcdCrLf();
}
chFlush();
for(m = 0; m < 80; m++)
{
editBuf[m] = '\0';
}
m = 0;
flshCnt = 0;
digitalWrite(14, 0);
eSq = 2;
}
}
break;
case 2: //INPUT
while(keyboard.available())
{
ch = keyboard.read();
chConvt();
if(ch != '\0')
{
switch(ch)
{
case PS2_ESC: //QUIT
chFlush();
msNo = -1;
esc = 0; digitalWrite(14, 0);
eSq = 0;
break;
case PS2_DOWNARROW: //OVERWRITE?
if(x != 0)
{
lcdCrLf();
}
msNo_ = msNo;
msNo = 21;
m = 0;
eSq = 3;
break;
case '\r':
if(msNo == 10)
{
if(m < 16 )
{
editBuf[m] = ch;
lcdCrLf();
m++;
}
}
else if(msNo == 15 || msNo == 16)
{
if(m < 80)
{
editBuf[m] = ch;
lcdCrLf();
m++;
}
}
else
{
if(m < 32)
{
editBuf[m] = ch;
lcdCrLf();
m++;
}
}
break;
case PS2_BACKSPACE:
if(m > 0)
{
if(x > 0 || y > 0)
{
m--;
editBuf[m] = '\0';
lcdBs();
}
}
break;
case PS2_RIGHTARROW:
break;
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
break;
default:
if(msNo == 10)
{
if(m < 16 )
{
editBuf[m] = ch;
lcdChOut();
m++;
}
}
else if(msNo == 15 || msNo == 16)
{
if(m < 80)
{
editBuf[m] = ch;
lcdChOut();
m++;
}
}
else
{
if(m < 32)
{
editBuf[m] = ch;
lcdChOut();
m++;
}
}
break;
}
}
}
break;
case 3: //ALERT
ch = ms[msNo][m]; //READ MESSAGE
if(ch == '\0') //END OF MESSAGE
{
msNo = msNo_;
if(x != 0)
{
lcdCrLf();
}
chFlush();
eSq = 4;
}
else
{
lcdChOut();
delay(75); //--
m++;
}
break;
case 4: //CONFIRM
while(keyboard.available())
{
ch = keyboard.read();
if(ch != '\0')
{
if(ch == PS2_ESC) //QUIT
{
chFlush();
esc = 0; digitalWrite(14, 0);
eSq = 0;
}
else if(ch == PS2_DOWNARROW) //TYPE AGAIN - SAVE
{
int startAddr = addrTb[msNo];
if(msNo == 10)
{
for(m = 0; m < 16; m++)
{
ms[msNo][m] = editBuf[m];
}
}
else if(msNo == 15 || msNo == 16)
{
for(m = 0; m < 80; m++)
{
ms[msNo][m] = editBuf[m];
}
Serial.println(startAddr);
for(m = 0; m < 80; m++)
{
EEPROM.write(startAddr + m, editBuf[m]);
}
EEPROM.write(startAddr + 80, '\0');
Serial.println("SAVED!");
}
else
{
for(m = 0; m < 32; m++)
{
ms[msNo][m] = editBuf[m];
}
Serial.println(startAddr);
for(m = 0; m < 32; m++)
{
EEPROM.write(startAddr + m, editBuf[m]);
}
EEPROM.write(startAddr + 32, '\0');
Serial.println("SAVED!");
}
msNo = 22;
m = 0;
eSq = 5;
}
}
}
break;
case 5: //DONE
ch = ms[msNo][m]; //READ MESSAGE
if(ch == '\0') //END OF MESSAGE
{
if(x != 0)
{
lcdCrLf();
}
chFlush();
esc = 0; digitalWrite(14, 0); //RETURN
eSq = 0;
}
else
{
lcdChOut();
delay(120); //--
m++;
}
break;
}
}
else if(keyboard.available())
{
ch = keyboard.read();
chConvt();
if(ch != '\0')
{
if(ch == PS2_ESC) //HANDLES [Esc] KEY
{
esc = esc ^ 1;
digitalWrite(14, esc);
eSq = 0;
}
else if(esc == 1)
{
if(ch >= 48 && ch <= 57) //'0'-'9'
{
msNo = ch - 48; //WHEN esc=1 AND A NUMBER KEY IS TYPED, START MESSAGE PLAYBACK
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 80; i++)
{
editBuf[i] = '\0';
}
//--
if(x != 0)
{
lcdCrLf();
}
eSq = 1;
}
else if(ch >= 14 && ch <= 23) //'F1'-'F10'
{
msNo = ch - 4; //WHEN esc=1 AND A FUNCTION KEY IS TYPED, START MESSAGE PLAYBACK
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 80; i++)
{
editBuf[i] = '\0';
}
//--
if(x != 0)
{
lcdCrLf();
}
eSq = 1;
}
}
else if(esc == 0)
{
if(ch >= 14 && ch <= 23) //'F1'-'F10'
{
esc = 1;
digitalWrite(14, 1);
msNo = ch - 4; //WHEN esc=0 AND A FUNCTION KEY IS TYPED, START MESSAGE PLAYBACK
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 80; i++)
{
editBuf[i] = '\0';
}
//--
if(x != 0)
{
lcdCrLf();
}
eSq = 1;
}
}
}
}
}
else if(tRx == 1) //RX to TX
{
if(snd == 0)
{
if(tRL == 1) //1st loop
{
chFlush();
msNo = -1;
esc = 0; digitalWrite(14, 0);
eSq = 0;
digitalWrite(15, 1); //PTT ON
Timer1.attachInterrupt(timer1_interrupt, MARK); //SOUND ON
delay(180);
//--
baudot = B01000; //-- CR --
ti = 0; snd = 1;
//--
tRL = 2;
}
else if(tRL == 2) //2nd loop
{
lcdCrLf();
//--
baudot = B00010; //-- LF --
ti = 0; snd = 1;
//--
tRL = 3;
}
else if(tRL == 3) //3rd loop
{
fig_1 = 0;
//--
baudot = B11111; //-- LTR (INITIALIZE "HIS/HER" DECODER) --
ti = 0; snd = 1;
//--
tRx = 2;
}
}
}
else if(tRx == 2) //TX
{
int i;
//snd 0,1
if(keyboard.available())
{
if(keyBuf[3] == '\0')
{
for(i = 0; i < 4; i++) //SEEK POSITION
{
if(keyBuf[i] == '\0')
{
break;
}
}
char ch3 = keyboard.read();
if(ch3 == PS2_ESC) //CHECK [ESC]
{
if(esc == 1)
{
msNo = -1;
n = 0;
esc = 0; digitalWrite(14, 0);
}
else
{
esc = 1; digitalWrite(14, 1);
}
}
else
{
keyBuf[i] = ch3; //PUSH
}
}
}
if(snd == 0)
{
if(shift == 1 || crLf == 1) //TOP PRIORITY (WHEN 2ND BYTE IS NEEDED)
{
chSend2();
}
else if(esc == 1 && msNo >= 0) //HANDLES MEMORY MESSAGES
{
if(digitalRead(18) == 1) //CHECK SW
{
msNo = -1;
n = 0;
goto exitTx;
}
while(keyBuf[0] != '\0') //ALWAYS CHECK KEYBOARD
{
//--keyBuf.read
ch2 = keyBuf[0];
for(i = 0; i < 4; i++)
{
keyBuf[i] = keyBuf[i + 1];
}
//--
if(ch2 >= 48 && ch2 <= 57) //'0'-'9'
{
if(n < 7)
{
mnBuf[n] = ch2; //REGISTER ADDITIONAL MESSAGE-NUMBERS, 7 NUMBERS AT MAXIMUM
n++;
}
}
else if(ch2 >= 14 && ch2 <= 23) //'F1'-'F10'
{
if(n < 7)
{
mnBuf[n] = ch2; //REGISTER ADDITIONAL MESSAGE-NUMBERS, 7 NUMBERS AT MAXIMUM
n++;
}
}
}
ch = ms[msNo][m]; //READ MESSAGE
if(ch == '\0') //END OF MESSAGE
{
if(m == 0 && n == 0) //EMPTY CH
{
flshCnt = 0;
empCh = true;
esc = 0;
}
else if(n == 0) //NO MESSAGE-NUMBER, EXIT
{
esc = 0; digitalWrite(14, 0);
}
msNo = -1;
}
if(msNo >= 0) //--SEND MEMORY--
{
chTableT();
chSend1();
m++;
}
}
else if(esc == 1 && n > 0) //COMPLETED SENDING <ONE> MESSAGE, AND OTHERS STILL REMAIN
{
ch = mnBuf[o]; //READ NUMBER
if(ch >= 48 && ch <= 57) //'0'-'9'
{
msNo = ch - 48; //SPECIFY THE NEXT
m = 0;
o++;
}
else if(ch >= 14 && ch <= 23) //'F1'-'F10'
{
msNo = ch - 4; //SPECIFY THE NEXT
m = 0;
o++;
}
else if(ch == '\0') //END OF MESSAGE-NUMBERS, EXIT
{
n = 0;
esc = 0; digitalWrite(14, 0);
}
}
else if(keyBuf[0] != '\0') //COMPLETED SENDING <ALL> MESSAGES, AND KEYBOARD IS TYPED
{
if(digitalRead(18) == 1) //CHECK SW
{
goto exitTx;
}
//--keyBuf.read
ch = keyBuf[0];
for(i = 0; i < 4; i++)
{
keyBuf[i] = keyBuf[i + 1];
}
//--
chConvt();
if(ch != '\0')
{
chTableT();
if(esc == 1)
{
if(ch >= 48 && ch <= 57) //'0'-'9'
{
msNo = ch - 48; //WHEN esc=1 AND A NUMBER KEY IS TYPED, START SENDING A NEW MESSAGE
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 7; i++)
{
mnBuf[i] = '\0';
}
//--
}
else if(ch >= 14 && ch <= 23) //'F1'-'F10'
{
msNo = ch - 4; //WHEN esc=1 AND A FUNCTION KEY IS TYPED, START SENDING A NEW MESSAGE
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 7; i++)
{
mnBuf[i] = '\0';
}
//--
}
}
else if(esc == 0)
{
if(ch >= 14 && ch <= 23) //'F1'-'F10'
{
esc = 1;
digitalWrite(14, 1);
msNo = ch - 4; //WHEN esc=0 AND A FUNCTION KEY IS TYPED, START 20CH MEMORY MODE
//--Ini
m = 0;
o = 0;
for(int i = 0; i < 7; i++)
{
mnBuf[i] = '\0';
}
//--
}
else if(ch == PS2_DOWNARROW) //SAVE LAST WORD TO [F1]
{
int m;
int i;
int msNo = 10; //[F1]
int endPos;
if(lcdType == 0){i = y * 16 + x;} //CALC POSITION
else if(lcdType == 1){i = y * 20 + x;}
endPos = i;
//SEEK LAST WORD
i--;
while(c[i] == ' ' || c[i] == '\0' || c[i] == '\r' && i >= 0)
{
i--;
}
while(c[i] != ' ' && c[i] != '\0' && c[i] != '\r' && i >= 0)
{
i--;
}
i++;
for(m = 0; m < 16; m++) //CLEAR [F1]
{
ms[msNo][m] = '\0';
}
m = 0;
while(c[i] != ' ' && c[i] != '\0' && c[i] != '\r' && i < endPos) //SAVE LAST WORD + ONE SPACE
{
ms[msNo][m] = c[i];
i++;
m++;
if(m == 16)
{
break;
}
}
if(m < 16)
{
ms[msNo][m] = ' ';
}
//DONE
digitalWrite(14, 1);
flshCnt = 0;
f1Stord = true;
}
else if(ch == PS2_RIGHTARROW || ch == PS2_BACKSPACE) //IGNORE THESE KEYS
{
/////
}
else //--SEND FROM KEYBOARD--
{
chSend1();
}
}
}
}
else
{
if(digitalRead(18) == 1) //CHECK SW
{
exitTx: //-LABEL-
delay(370); //LONG TONE
digitalWrite(15, 0); //PTT OFF
Timer1.detachInterrupt(); //SOUND OFF
esc = 0; digitalWrite(14, 0);
snd = 0;
tRx = 0;
}
else //NOTHING TO PROCESS, DIDDLE
{
if(ddl == 1 && ddCnt > ddItv)
{
fig_1 = 0;
baudot = B11111; //LTR (DIDDLE)
ti = 0; snd = 1;
}
}
}
}
}
}
// -- END OF THE SKETCH --
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////