Morse Code

char morse_a[] = ".-";
char morse_b[] = "-...";
char morse_c[] = "-.-.";
char morse_d[] = "-..";
char morse_e[] = ".";
char morse_f[] = "..-.";
char morse_g[] = "--.";
char morse_h[] = "....";
char morse_i[] = "..";
char morse_j[] = ".---";
char morse_k[] = "-.-";
char morse_l[] = ".-..";
char morse_m[] = "--";
char morse_n[] = "-.";
char morse_o[] = "---";
char morse_p[] = ".--.";
char morse_q[] = "--.-";
char morse_r[] = ".-.";
char morse_s[] = "...";
char morse_t[] = "-";
char morse_u[] = "..-";
char morse_v[] = "...-";
char morse_w[] = ".--";
char morse_x[] = "-..-";
char morse_y[] = "-.--";
char morse_z[] = "--..";

void setup() {
  Serial.begin(9600);

  String s;
  char t[] = ".";
  char u[] = "-";
  char v[] = ".-/-... -.-./-..";
  char w[] = "--/---/.-._=/.../. -.-./---/-../.";
  char x[] = ".- -.../---/.--/.-.. ---/..-. .--././-/..-/-./../.-/...";
  char y[] = "--/---/.-./.../......... -.-./---/-../.";
  char z[] = "--/---/.-./.../. -.-./---/-../..........";

  s = morse2ascii(t); Serial.println (s);
  s = morse2ascii(u); Serial.println (s);
  s = morse2ascii(v); Serial.println (s);
  s = morse2ascii(w); Serial.println (s);
  s = morse2ascii(x); Serial.println (s);
  s = morse2ascii(y); Serial.println (s);
  s = morse2ascii(z); Serial.println (s);

}

char morse2char (String s) {
  if (s.equals(morse_a)) {
    return 'a';
  }
  else if (s.equals(morse_b)) {
    return 'b';
  }
  else if (s.equals(morse_c)) {
    return 'c';
  }
  else if (s.equals(morse_b)) {
    return 'd';
  }
  else if (s.equals(morse_e)) {
    return 'e';
  }
  else if (s.equals(morse_f)) {
    return 'f';
  }
  else if (s.equals(morse_g)) {
    return 'g';
  }
  else if (s.equals(morse_h)) {
    return 'h';
  }
  else if (s.equals(morse_i)) {
    return 'i';
  }
  else if (s.equals(morse_j)) {
    return 'j';
  }
  else if (s.equals(morse_k)) {
    return 'k';
  }
  else if (s.equals(morse_l)) {
    return 'l';
  }
  else if (s.equals(morse_m)) {
    return 'm';
  }
  else if (s.equals(morse_n)) {
    return 'n';
  }
  else if (s.equals(morse_o)) {
    return 'o';
  }
  else if (s.equals(morse_p)) {
    return 'p';
  }
  else if (s.equals(morse_q)) {
    return 'q';
  }
  else if (s.equals(morse_r)) {
    return 'r';
  }
  else if (s.equals(morse_s)) {
    return 's';
  }
  else if (s.equals(morse_t)) {
    return 't';
  }
  else if (s.equals(morse_u)) {
    return 'u';
  }
  else if (s.equals(morse_v)) {
    return 'v';
  }
  else if (s.equals(morse_w)) {
    return 'w';
  }
  else if (s.equals(morse_x)) {
    return 'x';
  }
  else if (s.equals(morse_y)) {
    return 'y';
  }
  else if (s.equals(morse_z)) {
    return 'z';
  }
  else {
    return '#';
  }
}

String morse2ascii (String m) {
  String next = "";
  String result = "";
  for (int i = 0; i < m.length(); i++) {

    if (m[i] == ".") {
      next += m[i];
    }

    else  (m[i] == "-"); {
      next += m[i];
    }

    if  (m[i] == "/")  {
      result += morse2char (next);
      next = "";
    }

    else (m[i] == " "); {
      result += morse2char (next);
      result += ' ';
      next = "";
    }

    return result += morse2char (next);
  }
}

void loop() {
}

This is hard for me to explain so please be patient with me and I'll try my best.

My goal here is to get the program to print out a string of Morse into characters e.g

" char x[] = ".- -.../---/.--/.-.. ---/..-. .--././-/..-/-./../.-/..."; "

So this should print : "A BOWL OF PETUNIAS"

A space symbols a new word
A "/" symbols a new character

As you can see I've already wrote the code to change the Morse into characters

"char morse2char (String s)"

and now I'm trying to get the program to take each character and build them into a string using

"String morse2ascii (String m)"

So as best as I can explain it

If its a "."
hold the character and move onto next

if its a "-"
hold the character and move onto next

if its a "/"
Store previous characters in String next = "";

if its a " "
Store previous characters in String next = "";
if no more characters return the string

but it's only printing the first Morse character

String morse2ascii (String m) {
  String next = "";
  String result = "";
  for (int i = 0; i < m.length(); i++) {

    if (m[i] == ".") {
      next += m[i];
    }

    else  (m[i] == "-"); {
      next += m[i];
    }

    if  (m[i] == "/")  {
      result += morse2char (next);
      next = "";
    }

    else (m[i] == " "); {
      result += morse2char (next);
      result += ' ';
      next = "";
    }

    return result += morse2char (next);
  }
}

It's this piece of code here that is causing the problems.
Can you see any obvious mistakes I've made?

I'm sorry if this makes no sense, please do ask if something needs clearing up more.

Use of Strings is not recommended for Arduino. Strings cause memory problems and will eventually cause the Arduino to crash.

The C/C++ language provides excellent support for C-string handling (zero terminated character arrays). Good intro here.

Several Morse code reader programs have already been written, if you wish to take a look at what other people have done. Here is one that decodes signals off the air and prints ASCII. A bit clumsy, but if it works, fine.

    else  (m[i] == "-"); {

The semicolon ends the else clause. The stuff that follows it in the braces will be executed whether or not the else condition is true. You have two instances of this.

Also, the return statement is inside the for loop so the code will return from the function after one pass through the loop.

Pete

Okay, I've sorted the return statement inside the for loop and that's showing more promising results, but I kinda get what you're saying with the if and else statements, but I don't know how to write them or lay them out, I've tried every order and way I can think of.

Can you help me out there?

Remove those two semicolons.

Pete

LordCloud:
I'm sorry if this makes no sense, please do ask if something needs clearing up more.

First of all, here is a better way to handle morse and the characters it represents (from one of my projects):

static struct {
	const char chr; // the ASCII character
	const char *str; // the string of dots and dashes
} table[] = {
	{ 'A', ".-" },
	{ 'B', "-..." },
	{ 'C', "-.-." },
	{ 'D', "-.." },
	{ 'E', "." },
	{ 'F', "..-." },
	{ 'G', "--." },
	{ 'H', "...." },
	{ 'I', ".." },
	{ 'J', ".---" },
	{ 'K', "-.-" },
	{ 'L', ".-.." },
	{ 'M', "--" },
	{ 'N', "-." },
	{ 'O', "---" },
	{ 'P', ".--." },
	{ 'Q', "--.-" },
	{ 'R', ".-." },
	{ 'S', "..." },
	{ 'T', "-" },
	{ 'U', "..-" },
	{ 'V', "...-" },
	{ 'W', ".--" },
	{ 'X', "-..-" },
	{ 'Y', "-.--" },
	{ 'Z', "--.." },
	{ '0', "-----" },
	{ '1', ".----" },
	{ '2', "..---" },
	{ '3', "...--" },
	{ '4', "....-" },
	{ '5', "....." },
	{ '6', "-...." },
	{ '7', "--..." },
	{ '8', "---.." },
	{ '9', "----." },
	{ '.', ".-.-.-" },
	{ ',', "--..--" },
	{ ':', "---..." },
	{ '?', "..--.." },
	{ '\'', ".----." },
	{ '-', "-...-" },
	{ '/', "-..-." },
};

To access members of the struct, you do this:

If you want the letter "A" (index 0):
Pointer to the string ".-" = table[0].str

Pointer to the character "A" (ascii 65) = table[0].chr

Size of table (to iterate through it):
size = (sizeof (table) / sizeof (*table))

Now, what you need to do is take your incoming string, separate out letter groups (assuming you have a space between dits and dahs) like this (sp = space)
"-.-. sp --.- sp -.. sp . sp"
So your first character group is "-.-." (letter C). Then, scan through the table character by character and find a match to "table[index].str" and when you have the match, it's letter value is table[index].chr.

Also, check out THIS link. <- note he's got some errors in his table for example "K" is wrong.

Make sense?

el_supremo:
Remove those two semicolons.

Pete

But then I just get an error if I remove them telling me there is an expected ";" so this doesn't really work.

You haven't shown us your "corrected" code, so we can't help.

AWOL:
You haven't shown us your "corrected" code, so we can't help.

Thats the problem. It's not "corrected" because it's still not working, but for the sake of understanding.

String morse2ascii (String m) {
  String next = "";
  String result = "";
  for (int i = 0; i < m.length(); i++) {

    if (m[i] == ".") {
      next += m[i];
    }

    else  (m[i] == "-") {
      next += m[i];
    }

    if  (m[i] == "/")  {
      result += morse2char (next);
      next = "";
    }

    else (m[i] == " ") {
      result += morse2char (next);
      result += ' ';
      next = "";
    }

  }
  
  return result += morse2char (next);
}

That's what the code looks like now, after what Pete has advised me to do.

  1. Put the "return" outside the loop
  2. Remove the 2 semi-colons.

This is the error.

Arduino: 1.8.5 (Windows 10), Board: "Arduino/Genuino Uno"

C:\Users\coo12\Desktop\Morse\Morse.ino: In function 'String morse2ascii(String)':

C:\Users\coo12\Desktop\Morse\Morse.ino:153:17: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]

     if (m[i] == ".") {

                 ^

C:\Users\coo12\Desktop\Morse\Morse.ino:157:20: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]

     else  (m[i] == "-") {

                    ^

Morse:157: error: expected ';' before '{' token

     else  (m[i] == "-") {

                         ^

C:\Users\coo12\Desktop\Morse\Morse.ino:161:18: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]

     if  (m[i] == "/")  {

                  ^

C:\Users\coo12\Desktop\Morse\Morse.ino:166:19: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]

     else (m[i] == " ") {

                   ^

Morse:166: error: expected ';' before '{' token

     else (m[i] == " ") {

                        ^

exit status 1
expected ';' before '{' token

it looks like rather than this:

    if (m[i] == ".") {
      next += m[i];
    }

    else  (m[i] == "-") {
      next += m[i];
    }

You need:

    if (m[i] == ".") {
      next += m[i];
    }

    else if  (m[i] == "-") {
      next += m[i];
    }

That should get it to compile at least

you've tried to put a condition after your else statement:

else (m[i] == " ") {

you may want to investigate the proper syntax of an if statement

if (someStatement)
{

}
else if(someStatement)
{

}
else if(someStatement)
{

{
else // else executes unconditionally if none of the prior ifs executed
{

}
String morse2ascii (String m) {
  String next = "";
  String result = "";
  for (int i = 0; i < m.length(); i++) {

    if (m[i] == ".") {
      next += m[i];
    }

    else if  (m[i] == "-") {
      next += m[i];
    }

    else if  (m[i] == "/")  {
      result += morse2char (next);
      next = "";
    }

    else (m[i] == " "); {
      result += morse2char (next);
      result += ' ';
      next = "";
    }

  }
  
  return result += morse2char (next);
}

Sorry I should have specified that I have also tried it this way and every other way and it complies but still doesn't work.

Something is wrong and I just don't see it.

BulldogLowell:
you've tried to put a condition after your else statement:

else (m[i] == " ") {

you may want to investigate the proper syntax of an if statement

if (someStatement)

{

}
else if(someStatement)
{

}
else if(someStatement)
{

{
else // else executes unconditionally if none of the prior ifs executed
{

}

LordCloud:
Something is wrong and I just don't see it.

yes, this line is f'ed up:

else (m[i] == " "); {

coincidentally, the error code points there too...

Morse:166: error: expected ';' before '{' token

     else (m[i] == " ") {

                        ^

exit status 1
expected ';' before '{' token

the rest are just warnings...

BulldogLowell:
yes, this line is f'ed up:

else (m[i] == " "); {

coincidentally, the error code points there too...

Morse:166: error: expected ';' before '{' token

else (m[i] == " ") {

^

exit status 1
expected ';' before '{' token




the rest are just warnings...

I am aware of this, that's not my problem.

My problem is Pete told me to remove the semi-colons
Code didn't work.

I ordered it as

if
else if
else if
else

The code compiled but didn't work how it's suppose to.

I added the semicolon on the last else statement as the error message suggested.
Code complies, Still not working.

LordCloud:
I added the semicolon on the last else statement as the error message suggested.
Code complies, Still not working.

well, you didn't bother to show that, and what do you think that did to actually fix any problem there?

Still not working?

Why the heck (despite the good advice from other forum members) are you working with the String class?

I mean... why bother with using Strings if you then go and treat it like an array anyways?!?!?

your project is so much easier if you used C strings.

LordCloud:
I am aware of this, that's not my problem.

Also, read up on arrays and avoid repetitious code like this:

char morse2char (String s) {
  if (s.equals(morse_a)) {
    return 'a';
  }
  else if (s.equals(morse_b)) {
    return 'b';
  }
  else if (s.equals(morse_c)) {
    return 'c';
  }
  else if (s.equals(morse_b)) {
    return 'd';
  }
  else if (s.equals(morse_e)) {
    return 'e';
  }
  else if (s.equals(morse_f)) {
    return 'f';
  }
  else if (s.equals(morse_g)) {
    return 'g';
  }
  else if (s.equals(morse_h)) {
    return 'h';
  }
  else if (s.equals(morse_i)) {
    return 'i';
  }
  else if (s.equals(morse_j)) {
    return 'j';
  }
  else if (s.equals(morse_k)) {
    return 'k';
  }
  else if (s.equals(morse_l)) {
    return 'l';
  }
  else if (s.equals(morse_m)) {
    return 'm';
  }
  else if (s.equals(morse_n)) {
    return 'n';
  }
  else if (s.equals(morse_o)) {
    return 'o';
  }
  else if (s.equals(morse_p)) {
    return 'p';
  }
  else if (s.equals(morse_q)) {
    return 'q';
  }
  else if (s.equals(morse_r)) {
    return 'r';
  }
  else if (s.equals(morse_s)) {
    return 's';
  }
  else if (s.equals(morse_t)) {
    return 't';
  }
  else if (s.equals(morse_u)) {
    return 'u';
  }
  else if (s.equals(morse_v)) {
    return 'v';
  }
  else if (s.equals(morse_w)) {
    return 'w';
  }
  else if (s.equals(morse_x)) {
    return 'x';
  }
  else if (s.equals(morse_y)) {
    return 'y';
  }
  else if (s.equals(morse_z)) {
    return 'z';
  }
  else {
    return '#';
  }
}

that function should be no more than a few lines of code.

char morse2char (String s) {
  if (s.equals(morse_a)) {
    return 'a';
  }
  else if (s.equals(morse_b)) {
    return 'b';
  }
  else if (s.equals(morse_c)) {
    return 'c';
  }......

If you want to test a lot of conditions, you should use switch/case rather than a bunch of "if/then" statements.

For example, say the char "c" contains a letter:

switch (c) {
    case: 'A': {
        // send "dit-dah"
        break;
    }
    case 'B': {
        // send "dah-dit-dit-dit"
        break;
    }
    case 'C': {
        // send "dah-dit-dah-dit"
        break;
    }
    // all the rest
    default: {
        break; // required default case if nothing else matches
    }
}

Another thing: You are trying to compare a character to a cstring:

   else (m[i] == " ") {

This is an error. What you need is this:

   else (m[i] == ' ') {

Note the single quote. There is a big difference. " " is a c string composed of two bytes: 0x20 and 0x00 (the space and a terminating null). ' ' is a single byte of 0x20 (a space character).

See the difference. You were asking the program to compare a byte to a string which, of course, it cannot do.

Hope this helps.

krupski:
If you want to test a lot of conditions, you should use switch/case rather than a bunch of "if/then" statements.

an array and a simple function:

char decodeMorseLetter(const char* l)
{
  for (int i = 0; i < 26; i++)
  {
    if (strcmp(l, morseLetters[i].morseString) == 0)
    {
      return morseLetters[i].letter;
    }
  }
  return NULL;
}

with data like this:

struct Code{
  const char* morseString;
  char letter;
};

const Code morseLetters[] = {
  {".-",    'a'},
  {"-...",  'b'},
  {"-.-.",  'c'},
  {"-..",   'd'},
  {".",     'e'},
  {"..-.",  'f'},
  {"--.",   'g'},
  {"....",  'h'},
  {"..",    'i'},
  {".---",  'j'},
  {"-.-",   'k'},
  {".-..",  'l'},
  {"--",    'm'},
  {"-.",    'n'},
  {"---",   'o'},
  {".--.",  'p'},
  {"--.-",  'q'},
  {".-.",   'r'},
  {"...",   's'},
  {"-",     't'},
  {"..-",   'u'},
  {"...-",  'v'},
  {".--",   'w'},
  {"-..-",  'x'},
  {"-.--",  'y'},
  {"--..",  'z'},
};

BulldogLowell:
an array and a simple function:

char decodeMorseLetter(const char* l)

{
 for (int i = 0; i < 26; i++)
 {
   if (strcmp(l, morseLetters[i].morseString) == 0)
   {
     return morseLetters[i].letter;
   }
 }
 return NULL;
}

Yes of course it's cleaner to iterate through the array.

What I was commenting on was REPLACING a bunch of "if/then" statements with "switch/case" (relevant to the way the OP was trying to do it, not relevant to using an array as suggested by several of us).