//////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // JI3BNB RTTY EnDECODER for ARDUINO UNO - TX & RX VERSION - // 2018.03.20 v6.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; //IO2 = "DATA" PIN const int IRQpin = 3; //IO3 = "CLOCK" PIN (!!DO NOT CAHNGE THIS) const boolean 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 //////////////////////////////////////////////////////////////////////////////// // A5(=D19) : DECODER INPUT // 0/5V TTL LEVEL (NOT AUDIO SIGNAL) // EXTERNAL DEMODULATOR REQUIRED //////////////////////////////////////////////////////////////////////////////// // "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; 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 dsp; 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 rSq; 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 AND DECODER 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; } if(tRx == 0) { ti++; if(rSq == 0 && digitalRead(19) == 0) { rSq = 1; ti = 0; } if(rSq == 1 && ti == 10) { if(digitalRead(19) == 0) { rSq = 2; ti = 0; } else { rSq = 0; } } if(rSq == 2 && ti == 22) { bitWrite(baudot, 0, digitalRead(19)); } else if(rSq == 2 && ti == 44) { bitWrite(baudot, 1, digitalRead(19)); } else if(rSq == 2 && ti == 66) { bitWrite(baudot, 2, digitalRead(19)); } else if(rSq == 2 && ti == 88) { bitWrite(baudot, 3, digitalRead(19)); } else if(rSq == 2 && ti == 110) { bitWrite(baudot, 4, digitalRead(19)); if(eSq == 0) { dsp = 1; } } else if(rSq == 2 && ti == 135) { rSq = 0; } } 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 { if(ch == '@' ){ch = '"' ;} else if(ch == '^' ){ch = '&' ;} else if(ch == '&' ){ch = '\'';} else if(ch == '*' ){ch = '(' ;} else if(ch == '(' ){ch = ')' ;} else if(ch == ')' ){ch = '~' ;} else if(ch == '_' ){ch = '=' ;} else if(ch == '=' ){ch = '^' ;} else if(ch == '+' ){ch = '\0';} else if(ch == '[' ){ch = '@' ;} else if(ch == '{' ){ch = '`' ;} else if(ch == ']' ){ch = '[' ;} else if(ch == '}' ){ch = '{' ;} else if(ch == ':' ){ch = '+' ;} else if(ch == '\''){ch = ':' ;} else if(ch == '"' ){ch = '*' ;} else if(ch == '\\'){ch = ']' ;} else if(ch == '|' ){ch = '}' ;} } if(usFig == 1) //"Fldigi" SOFTWARE 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 chTableR() { if(usFig == 1) //"Fldigi" COMPATIBLE { ch = '\0'; if(baudot == B11111){fig = 0; } //LETTERS else if(baudot == B11011){fig = 1; } //FIGURES else if(baudot == B01000){ } //CR else if(baudot == B00010){ch = ' ';} //LF else if(baudot == B00100){ch = ' ';} //SPACE if(fig == 0) { if(baudot == B00011){ch = 'A';} else if(baudot == B11001){ch = 'B';} else if(baudot == B01110){ch = 'C';} else if(baudot == B01001){ch = 'D';} else if(baudot == B00001){ch = 'E';} else if(baudot == B01101){ch = 'F';} else if(baudot == B11010){ch = 'G';} else if(baudot == B10100){ch = 'H';} else if(baudot == B00110){ch = 'I';} else if(baudot == B01011){ch = 'J';} else if(baudot == B01111){ch = 'K';} else if(baudot == B10010){ch = 'L';} else if(baudot == B11100){ch = 'M';} else if(baudot == B01100){ch = 'N';} else if(baudot == B11000){ch = 'O';} else if(baudot == B10110){ch = 'P';} else if(baudot == B10111){ch = 'Q';} else if(baudot == B01010){ch = 'R';} else if(baudot == B00101){ch = 'S';} else if(baudot == B10000){ch = 'T';} else if(baudot == B00111){ch = 'U';} else if(baudot == B11110){ch = 'V';} else if(baudot == B10011){ch = 'W';} else if(baudot == B11101){ch = 'X';} else if(baudot == B10101){ch = 'Y';} else if(baudot == B10001){ch = 'Z';} } else if(fig == 1) { if(baudot == B10110){ch = '0' ;} else if(baudot == B10111){ch = '1' ;} else if(baudot == B10011){ch = '2' ;} else if(baudot == B00001){ch = '3' ;} else if(baudot == B01010){ch = '4' ;} else if(baudot == B10000){ch = '5' ;} else if(baudot == B10101){ch = '6' ;} else if(baudot == B00111){ch = '7' ;} else if(baudot == B00110){ch = '8' ;} else if(baudot == B11000){ch = '9' ;} else if(baudot == B00011){ch = '-' ;} else if(baudot == B11001){ch = '?' ;} else if(baudot == B01110){ch = ':' ;} else if(baudot == B01111){ch = '(' ;} else if(baudot == B10010){ch = ')' ;} else if(baudot == B11100){ch = '.' ;} else if(baudot == B01100){ch = ',' ;} else if(baudot == B11101){ch = '/' ;} //"Fldigi" SOFTWARE COMPATIBLE else if(baudot == B01001){ch = '$' ;} else if(baudot == B01011){ch = '\'';} else if(baudot == B01101){ch = '!' ;} else if(baudot == B10001){ch = '"' ;} else if(baudot == B10100){ch = '#' ;} else if(baudot == B11010){ch = '&' ;} else if(baudot == B11110){ch = ';' ;} else if(baudot == B00101){ } //BELL } } else if(usFig == 0) //"TONO THETA-5000E" COMPATIBLE { ch = '\0'; if(baudot == B11111){fig = 0; } //LETTERS else if(baudot == B11011){fig = 1; } //FIGURES else if(baudot == B01000){ } //CR else if(baudot == B00010){ch = ' ';} //LF else if(baudot == B00100){ch = ' ';} //SPACE if(fig == 0) { if(baudot == B00011){ch = 'A';} else if(baudot == B11001){ch = 'B';} else if(baudot == B01110){ch = 'C';} else if(baudot == B01001){ch = 'D';} else if(baudot == B00001){ch = 'E';} else if(baudot == B01101){ch = 'F';} else if(baudot == B11010){ch = 'G';} else if(baudot == B10100){ch = 'H';} else if(baudot == B00110){ch = 'I';} else if(baudot == B01011){ch = 'J';} else if(baudot == B01111){ch = 'K';} else if(baudot == B10010){ch = 'L';} else if(baudot == B11100){ch = 'M';} else if(baudot == B01100){ch = 'N';} else if(baudot == B11000){ch = 'O';} else if(baudot == B10110){ch = 'P';} else if(baudot == B10111){ch = 'Q';} else if(baudot == B01010){ch = 'R';} else if(baudot == B00101){ch = 'S';} else if(baudot == B10000){ch = 'T';} else if(baudot == B00111){ch = 'U';} else if(baudot == B11110){ch = 'V';} else if(baudot == B10011){ch = 'W';} else if(baudot == B11101){ch = 'X';} else if(baudot == B10101){ch = 'Y';} else if(baudot == B10001){ch = 'Z';} } else if(fig == 1) { if(baudot == B10110){ch = '0' ;} else if(baudot == B10111){ch = '1' ;} else if(baudot == B10011){ch = '2' ;} else if(baudot == B00001){ch = '3' ;} else if(baudot == B01010){ch = '4' ;} else if(baudot == B10000){ch = '5' ;} else if(baudot == B10101){ch = '6' ;} else if(baudot == B00111){ch = '7' ;} else if(baudot == B00110){ch = '8' ;} else if(baudot == B11000){ch = '9' ;} else if(baudot == B00011){ch = '-' ;} else if(baudot == B11001){ch = '?' ;} else if(baudot == B01110){ch = ':' ;} else if(baudot == B01111){ch = '(' ;} else if(baudot == B10010){ch = ')' ;} else if(baudot == B11100){ch = '.' ;} else if(baudot == B01100){ch = ',' ;} else if(baudot == B11101){ch = '/' ;} //"TONO THETA-5000E" COMPATIBLE else if(baudot == B00101){ch = '\'';} else if(baudot == B01001){ch = '$' ;} else if(baudot == B01101){ch = '!' ;} else if(baudot == B10001){ch = '+' ;} else if(baudot == B10100){ch = '#' ;} else if(baudot == B11010){ch = '&' ;} else if(baudot == B11110){ch = '=' ;} else if(baudot == B01011){ } //BELL } } } 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 (EXCEPT 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 if(x != 0) { lcdCrLf(); } 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(dsp == 1) { chTableR(); if(ch != '\0') { lcdChOut(); } dsp = 0; } } 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 if(x != 0) { lcdCrLf(); } esc = 0; digitalWrite(14, 0); snd = 0; rSq = 0; fig = 0; dsp = 0; tRx = 0; } else //NOTHING TO PROCESS, DIDDLE { if(ddl == 1 && ddCnt > ddItv) { fig_1 = 0; baudot = B11111; //LTR (DIDDLE) ti = 0; snd = 1; } } } } } }