#include <LiquidCrystal_I2C.h>
#include "Keypad.h"
#include <cstring>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
#define relayout 5
#define audioInPin 18
#define ledPin 19
#define speaker 17
#define DEFAULT_DELAY 300
const byte ROWS = 4;
const byte COLS = 4;
int x = 0;
int y = 0;
int minValue = 0;
int maxValue = 0;
int keyPressTime = 100;
String msg = "";
String alpha = "1/@_$%? ABC2 DEF3 GHI4 JKL5 MNO6 PQRS7 TUV8 WXYZ9 * 0# ";
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {27, 13, 16, 4};
byte colPins[COLS] = {33, 25, 26, 14};
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
const char* morseCode[] = {
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.",
"---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..",
".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", "-----"
};
const int numChar = sizeof(morseCode) / sizeof(morseCode[0]);
char buffer[100];
int bufferIndex = 0;
char receivedText[100];
int receivedTextIndex = 0;
float magnitude;
int magnitudeLimit = 100;
int magnitudeLimitLow = 100;
int realState = LOW;
int realStateBefore = LOW;
int filteredState = LOW;
int filteredStateBefore = LOW;
float coeff;
float Q1 = 0;
float Q2 = 0;
float sine;
float cosine;
float samplingFreq = 8928.0;
float targetFreq = 558.0;
float n = 48.0;
int testData[48];
int nbTime = 6;
long startTimeHigh;
long highDuration;
long lastHighDuration;
long highTimeAvg;
long lowTimeAvg;
long startTimeLow;
long lowDuration;
long lastStartTime = 0;
char code[100];
int codeIndex = 0;
int stop = LOW;
int wpm;
byte charUp[8] = {
B00100,
B01110,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte charDown[8] = {
B00000,
B00000,
B00000,
B00000,
B00100,
B11111,
B01110,
B00100
};
byte charUpDown[8] = {
B00100,
B01110,
B11111,
B00100,
B00100,
B11111,
B01110,
B00100
};
byte charEnter[8] = {
B11111,
B10101,
B10101,
B00000,
B11111,
B00110,
B01100,
B11111
};
byte menuLevel = 0;
byte menu = 1;
byte sub = 1;
int lcdindex = 0;
int line1[LCD_COLUMNS];
int line2[LCD_COLUMNS];
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.createChar(0, charUp);
lcd.createChar(1, charDown);
lcd.createChar(2, charUpDown);
lcd.createChar(3, charEnter);
updateLevel_0();
pinMode(relayout, OUTPUT);
digitalWrite(relayout, LOW);
pinMode(audioInPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
pinMode(speaker, OUTPUT);
digitalWrite(speaker, LOW);
noTone(speaker);
int k = (int)(0.5 + ((n * targetFreq) / samplingFreq));
float omega = (2.0 * PI * k) / n;
sine = sin(omega);
cosine = cos(omega);
coeff = 2.0 * cosine;
for (int LCDindex = 0; LCDindex < LCD_COLUMNS; LCDindex++) {
line1[LCDindex] = 32;
line2[LCDindex] = 32;
}
}
void loop() {
processKey();
strcpy(buffer, msg.c_str());
}
void postPrint() {
//x++;
if (x >= 16) {
if (y == 0) {
x = 0;
y = 1;
} else {
lcd.clear();
x = 0;
y = 0;
}
}
}
void processKey() {
char key = customKeypad.getKey();
if (isAlpha(key)) {
processKeys(key);
}
}
void parseKey(int minValue, int maxValue, char keyPress) {
int ch = minValue;
char key = keyPress;
if (keyPress == 'C') {
if (x > 0 || y > 0) {
x--;
lcd.setCursor(x, y);
lcd.print(" ");
msg.remove(msg.length() - 1);
}
} else {
for (int i = 0; i < keyPressTime; i++) {
if (key == keyPress) {
lcd.setCursor(x, y);
lcd.print(alpha[ch]);
ch++;
if (ch > maxValue) {
ch = minValue;
i = 0;
}
}
key = customKeypad.getKey();
delay(10);
}
x++;
msg += alpha[ch - 1];
postPrint();
}
}
void enterMSG() {
char key;
lcd.clear();
x = 0;
y = 0;
msg = "";
clearBuffer();
do {
key = customKeypad.getKey();
if (key == '1') {
parseKey(0, 7, key);
} else if (key == '2') {
parseKey(8, 12, key);
} else if (key == '3') {
parseKey(13, 17, key);
} else if (key == '4') {
parseKey(18, 22, key);
} else if (key == '5') {
parseKey(23, 27, key);
} else if (key == '6') {
parseKey(28, 32, key);
} else if (key == '7') {
parseKey(33, 38, key);
} else if (key == '8') {
parseKey(39, 43, key);
} else if (key == '9') {
parseKey(44, 49, key);
} else if (key == '0') {
parseKey(52, 54, key);
} else if (key == 'C') {
parseKey(50, 51, key);
}
} while (key != 'D');
}
void sendMorseCode(const char* text) {
for (int i = 0; text[i] != '\0'; i++) {
char ch = toLowerCase(text[i]);
if (ch >= 'a' && ch <= 'z') {
int index = ch - 'a';
sendMorseChar(morseCode[index]);
} else if (ch >= '0' && ch <= '9') {
int index = ch - '0' + 26;
sendMorseChar(morseCode[index]);
} else if (ch == '/') {
delay(1400);
}
delay(700);
}
}
void sendMorseChar(const char* morseChar) {
for (int i = 0; morseChar[i] != '\0'; i++) {
if (morseChar[i] == '.') {
digitalWrite(relayout, HIGH);
digitalWrite(ledPin, HIGH);
digitalWrite(speaker, HIGH);
tone(speaker, 558.0);
delay(200);
digitalWrite(relayout, LOW);
digitalWrite(ledPin, LOW);
digitalWrite(speaker, LOW);
noTone(speaker);
} else if (morseChar[i] == '-') {
digitalWrite(relayout, HIGH);
digitalWrite(ledPin, HIGH);
digitalWrite(speaker, HIGH);
tone(speaker, 558.0);
delay(600);
digitalWrite(relayout, LOW);
digitalWrite(ledPin, LOW);
digitalWrite(speaker, LOW);
noTone(speaker);
}
delay(200);
}
}
void recieveMorseCode() {
lcd.clear();
for (char index = 0; index < n; index++) {
testData[index] = analogRead(audioInPin);
}
for (char index = 0; index < n; index++) {
float Q0;
Q0 = coeff * Q1 - Q2 + (float)testData[index];
Q2 = Q1;
Q1 = Q0;
}
float magnitudeSquared = (Q1 * Q1) + (Q2 * Q2) - Q1 * Q2 * coeff;
magnitude = sqrt(magnitudeSquared);
Q2 = 0;
Q1 = 0;
if (magnitude > magnitudeLimitLow) {
magnitudeLimit = (magnitudeLimit + ((magnitude - magnitudeLimit) / 6));
}
if (magnitudeLimit < magnitudeLimitLow) {
magnitudeLimit = magnitudeLimitLow;
}
if (magnitude > magnitudeLimit * 0.6) {
realState = HIGH;
} else {
realState = LOW;
}
if (realState != realStateBefore) {
lastStartTime = millis();
}
if ((millis() - lastStartTime) > nbTime) {
if (realState != filteredState) {
filteredState = realState;
}
}
if (filteredState != filteredStateBefore) {
if (filteredState == HIGH) {
startTimeHigh = millis();
lowDuration = (millis() - startTimeLow);
}
if (filteredState == LOW) {
startTimeLow = millis();
highDuration = (millis() - startTimeHigh);
if (highDuration < (2 * highTimeAvg) || highTimeAvg == 0) {
highTimeAvg = (highDuration + highTimeAvg + highTimeAvg) / 3;
}
if (highDuration > (5 * highTimeAvg)) {
highTimeAvg = highDuration + highTimeAvg;
}
}
}
if (filteredState != filteredStateBefore) {
stop = LOW;
if (filteredState == LOW) {
if (highDuration < (highTimeAvg * 2) && highDuration > (highTimeAvg * 0.6)) {
strcat(code, ".");
Serial.print(".");
}
if (highDuration > (highTimeAvg * 2) && highDuration < (highTimeAvg * 6)) {
strcat(code, "-");
Serial.print("-");
wpm = (wpm + (1200 / ((highDuration) / 3))) / 2;
}
}
if (filteredState == HIGH) {
float lackTime = 1;
if (wpm > 25) {
lackTime = 1.0;
}
if (wpm > 30) {
lackTime = 1.2;
}
if (wpm > 35) {
lackTime = 1.5;
}
if (lowDuration > (highTimeAvg * (2 * lackTime)) && lowDuration < highTimeAvg * (5 * lackTime)) {
docode();
code[0] = '\0';
Serial.print("/");
}
if (lowDuration >= highTimeAvg * (5 * lackTime)) {
code[0] = '\0';
printascii(32);
Serial.println();
}
}
}
if ((millis() - startTimeLow) > (highDuration * 6) && stop == LOW) {
docode();
code[0] = '\0';
stop = HIGH;
}
if (filteredState == HIGH) {
digitalWrite(ledPin, HIGH);
tone(speaker, targetFreq);
} else {
digitalWrite(ledPin, LOW);
noTone(speaker);
}
updateInfoLineLcd();
realStateBefore = realState;
lastHighDuration = highDuration;
filteredStateBefore = filteredState;
}
void docode() {
if (strcmp(code, ".-") == 0) printascii(65);
if (strcmp(code, "-...") == 0) printascii(66);
if (strcmp(code, "-.-.") == 0) printascii(67);
if (strcmp(code, "-..") == 0) printascii(68);
if (strcmp(code, ".") == 0) printascii(69);
if (strcmp(code, "..-.") == 0) printascii(70);
if (strcmp(code, "--.") == 0) printascii(71);
if (strcmp(code, "....") == 0) printascii(72);
if (strcmp(code, "..") == 0) printascii(73);
if (strcmp(code, ".---") == 0) printascii(74);
if (strcmp(code, "-.-") == 0) printascii(75);
if (strcmp(code, ".-..") == 0) printascii(76);
if (strcmp(code, "--") == 0) printascii(77);
if (strcmp(code, "-.") == 0) printascii(78);
if (strcmp(code, "---") == 0) printascii(79);
if (strcmp(code, ".--.") == 0) printascii(80);
if (strcmp(code, "--.-") == 0) printascii(81);
if (strcmp(code, ".-.") == 0) printascii(82);
if (strcmp(code, "...") == 0) printascii(83);
if (strcmp(code, "-") == 0) printascii(84);
if (strcmp(code, "..-") == 0) printascii(85);
if (strcmp(code, "...-") == 0) printascii(86);
if (strcmp(code, ".--") == 0) printascii(87);
if (strcmp(code, "-..-") == 0) printascii(88);
if (strcmp(code, "-.--") == 0) printascii(89);
if (strcmp(code, "--..") == 0) printascii(90);
if (strcmp(code, ".----") == 0) printascii(49);
if (strcmp(code, "..---") == 0) printascii(50);
if (strcmp(code, "...--") == 0) printascii(51);
if (strcmp(code, "....-") == 0) printascii(52);
if (strcmp(code, ".....") == 0) printascii(53);
if (strcmp(code, "-....") == 0) printascii(54);
if (strcmp(code, "--...") == 0) printascii(55);
if (strcmp(code, "---..") == 0) printascii(56);
if (strcmp(code, "----.") == 0) printascii(57);
if (strcmp(code, "-----") == 0) printascii(48);
if (strcmp(code, "..--..") == 0) printascii(63);
if (strcmp(code, ".-.-.-") == 0) printascii(46);
if (strcmp(code, "--..--") == 0) printascii(44);
if (strcmp(code, "-.-.--") == 0) printascii(33);
if (strcmp(code, ".--.-.") == 0) printascii(64);
if (strcmp(code, "---...") == 0) printascii(58);
if (strcmp(code, "-....-") == 0) printascii(45);
if (strcmp(code, "-..-.") == 0) printascii(47);
if (strcmp(code, "-.--.") == 0) printascii(40);
if (strcmp(code, "-.--.-") == 0) printascii(41);
if (strcmp(code, ".-...") == 0) printascii(95);
if (strcmp(code, "...-..-") == 0) printascii(36);
if (strcmp(code, "...-.-") == 0) printascii(62);
if (strcmp(code, ".-.-.") == 0) printascii(60);
if (strcmp(code, "...-.") == 0) printascii(126);
if (strcmp(code, ".-.-") == 0) printascii(3);
if (strcmp(code, "---.") == 0) printascii(4);
if (strcmp(code, ".--.-") == 0) printascii(6);
}
void printascii(int asciinumber) {
int fail = 0;
if (LCD_LINES == 4 and LCD_COLUMNS == 16)fail = -4;
if (lcdindex > LCD_COLUMNS - 1) {
lcdindex = 0;
if (LCD_LINES == 4) {
for (int i = 0; i <= LCD_COLUMNS - 1 ; i++) {
lcd.setCursor(i, LCD_LINES - 3);
lcd.write(line2[i]);
line2[i] = line1[i];
}
}
for (int i = 0; i <= LCD_COLUMNS - 1 ; i++) {
lcd.setCursor(i + fail, LCD_LINES - 2);
lcd.write(line1[i]);
lcd.setCursor(i + fail, LCD_LINES - 1);
lcd.write(32);
}
}
line1[lcdindex] = asciinumber;
lcd.setCursor(lcdindex + fail, LCD_LINES - 1);
lcd.write(asciinumber);
lcdindex += 1;
}
void updateInfoLineLcd() {
int place;
if (LCD_LINES == 4) {
place = LCD_COLUMNS / 2;
} else {
place = 2;
}
if (wpm < 10) {
lcd.setCursor(place - 2, 0);
lcd.print("0");
lcd.setCursor(place - 1, 0);
lcd.print(wpm);
lcd.setCursor(place, 0);
lcd.print(" WPM");
} else {
lcd.setCursor(place - 2, 0);
lcd.print(wpm);
lcd.setCursor(place, 0);
lcd.print(" WPM ");
}
}
void processKeys(int keyPressed) {
switch (menuLevel) {
case 0:
switch (keyPressed) {
case 'D':
menu = 1;
menuLevel = 2;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'A':
break;
case 'B':
menu = 2;
menuLevel = 2;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'C':
menuLevel = 0;
updateLevel_0();
delay(DEFAULT_DELAY * 2);
break;
default:
break;
}
break;
case 1:
switch (keyPressed) {
case 'D':
sub = 1;
menuLevel = 2;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'A':
menu--;
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 'B':
menu++;
updateLevel_1();
delay(DEFAULT_DELAY);
break;
case 'C':
menuLevel = 0;
updateLevel_0();
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
case 2:
switch (keyPressed) {
case 'D':
if (menu == 1) {
if (sub == 1) {
lcd.clear();
lcd.print("Enter Msg");
delay(1000);
enterMSG();
delay(500);
lcd.clear();
menuLevel = 2;
updateLevel_2();
} else if (sub == 2) {
lcd.clear();
lcd.print("sending ...");
lcd.setCursor(0, 1);
delay(500);
lcd.clear();
lcd.print(buffer);
sendMorseCode(buffer);
menuLevel = 2;
updateLevel_2();
} else if (sub == 3) {
lcd.clear();
lcd.print("Sent/Msg");
lcd.setCursor(0, 1);
delay(500);
lcd.clear();
lcd.print(buffer);
delay(1000);
menuLevel = 2;
updateLevel_2();
} else if (sub == 4) {
lcd.clear();
lcd.print("Snd/Msg Deleted");
lcd.setCursor(0, 1);
msg = "";
clearBuffer();
delay(1000);
menuLevel = 2;
updateLevel_2();
}
} else if (menu == 2) {
if (sub == 1) {
lcd.clear();
lcd.print("recieving ...");
delay(500);
recieveMorseCode();
char key = customKeypad.getKey();
if (key == 'C') {
menuLevel = 2;
updateLevel_2();
}
} else if (sub == 2) {
lcd.clear();
lcd.print("Received Msg");
lcd.setCursor(0, 1);
delay(500);
lcd.clear();
lcd.print(receivedText);
char key = customKeypad.getKey();
if (key == 'C') {
menuLevel = 2;
updateLevel_2();
}
} else if (sub == 3) {
lcd.clear();
lcd.print("Rec/Msg Deleted");
lcd.setCursor(0, 1);
clearCode();
clearReceivedText();
delay(1000);
menuLevel = 2;
updateLevel_2();
}
}
delay(DEFAULT_DELAY);
break;
case 'A':
sub--;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'B':
sub++;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'C':
menuLevel = 1;
updateLevel_1();
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
default:
break;
}
}
void updateLevel_0() {
lcd.clear();
lcd.println("ELCTRO/MORSECODE");
lcd.setCursor(0, 1);
lcd.println("*** E S O T ***");
delay(DEFAULT_DELAY * 10);
lcd.clear();
lcd.println("\x03 to Snd/Morse ");
lcd.setCursor(0, 1);
lcd.println( "\x01 to Rec/Morse ");
}
void updateLevel_1() {
switch (menu) {
case 0:
menu = 1;
break;
case 1:
lcd.clear();
lcd.print(">Snd/Morse ");
lcd.setCursor(0, 1);
lcd.print("Rec/Morse ");
lcd.setCursor(15, 1);
lcd.write(1);
break;
case 2:
lcd.clear();
lcd.print("Snd/Morse ");
lcd.setCursor(0, 1);
lcd.print(">Rec/Morse ");
lcd.setCursor(15, 1);
lcd.write(0);
break;
case 3:
menu = 2;
break;
}
}
void updateLevel_2() {
switch (menu) {
case 0:
break;
case 1:
switch (sub) {
case 0:
break;
case 1:
lcd.clear();
lcd.print("Send MorseCode");
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(" Create");
lcd.setCursor(15, 1);
break;
case 2:
lcd.clear();
lcd.print("Send MorseCode");
lcd.setCursor(0, 1);
lcd.write(2);
lcd.print(" Send");
lcd.setCursor(15, 1);
break;
case 3:
lcd.clear();
lcd.print("Send MorseCode");
lcd.setCursor(0, 1);
lcd.write(2);
lcd.print(" Read");
lcd.setCursor(15, 1);
break;
case 4:
lcd.clear();
lcd.print("Send MorseCode");
lcd.setCursor(0, 1);
lcd.write(0);
lcd.print(" Delete");
lcd.setCursor(15, 1);
break;
default:
break;
}
break;
case 2:
switch (sub) {
case 0:
break;
case 1:
lcd.clear();
lcd.print("Recieve MorseCode");
lcd.setCursor(0, 1);
lcd.write(1);
lcd.print(" Recieving");
lcd.setCursor(15, 1);
break;
case 2:
lcd.clear();
lcd.print("Recieve MorseCode");
lcd.setCursor(0, 1);
lcd.write(2);
lcd.print(" Read");
lcd.setCursor(15, 1);
break;
case 3:
lcd.clear();
lcd.print("Recieve MorseCode");
lcd.setCursor(0, 1);
lcd.write(0);
lcd.print(" Delete");
lcd.setCursor(15, 1);
break;
default:
break;
}
break;
case 3:
sub = 2;
break;
}
}
void clearBuffer() {
for (int i = 0; i < bufferIndex; i++) {
buffer[i] = '\0';
}
bufferIndex = 0;
}
void clearCode() {
for (int i = 0; i < codeIndex; i++) {
code[i] = '\0';
}
codeIndex = 0;
}
void clearReceivedText() {
for (int i = 0; i < receivedTextIndex; i++) {
receivedText[i] = '\0';
}
receivedTextIndex = 0;
}