Decoding morse string into character string

Hey there,

I made a forum post earlier in regards to some of the issues I've been encountering whilst creating a Morse code encoder/decoder. I've tried to apply the advice I received but I'm making little to no progress.

Essentially, what I am trying to do is take a given string or two of Morse code that might look like this:

char t [] = "−−/−−−/.−.=/... /. −.−./−−−/−../.";
char u[] = "−−/−−−−−−−−−/.−./.../. −.−./−−−/−../.";

And then print the translated version of this to the serial.

Presently, my code is able to encode; to take a string of ASCII characters and translate them to code, but I'm doing this by simply using a switch statement and a for loop inside of an array so that I can switch each character.

The part that I am specifically struggling with is the fact that I do not know how I could decode; to take the Morse, which uses multiple characters to refer to the ASCII character, and use the switch and for loop method to decode the morse.

Here's my full code thus far:

// Here is where I create the library of 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[] = "--..";

// Here is where I convert regular ASCII characters into morse code
char * char2morse(char c) {
  switch (c) {
    case 'a':
      return morse_a;
      break;

    case 'b':
      return morse_b;
      break;

    case 'c':
      return morse_c;
      break;

    case 'd':
      return morse_d;
      break;

    case 'e':
      return morse_e;
      break;

    case 'f':
      return morse_f;
      break;

    case 'g':
      return morse_g;
      break;

    case 'h':
      return morse_h;
      break;

    case 'i':
      return morse_i;
      break;

    case 'j':
      return morse_j;
      break;

    case 'k':
      return morse_k;
      break;

    case 'l':
      return morse_l;
      break;

    case 'm':
      return morse_m;
      break;

    case 'n':
      return morse_n;
      break;

    case 'o':
      return morse_o;
      break;

    case 'p':
      return morse_p;
      break;

    case 'q':
      return morse_q;
      break;

    case 'r':
      return morse_r;
      break;

    case 's':
      return morse_s;
      break;

    case 't':
      return morse_t;
      break;

    case 'u':
      return morse_u;
      break;

    case 'v':
      return morse_v;
      break;

    case 'w':
      return morse_w;
      break;

    case 'x':
      return morse_x;
      break;

    case 'y':
      return morse_y;
      break;

    case 'z':
      return morse_z;
      break;

    case ' ':
      return " ";
    default:
      return "#";
  }
}
//Here is where I convert morse code into regular ASCII characters
char morse2char(String m) {
  if (m.equals(morse_a)) {
    return 'a';
  }
  else if (m.equals(morse_b)) {
    return 'b';
  }
  else if (m.equals(morse_c)) {
    return 'c';
  }
  else if (m.equals(morse_d)) {
    return 'd';
  }
  else if (m.equals(morse_e)) {
    return 'e';
  }
  else if (m.equals(morse_f)) {
    return 'f';
  }
  else if (m.equals(morse_g)) {
    return 'g';
  }
  else if (m.equals(morse_h)) {
    return 'h';
  }
  else if (m.equals(morse_i)) {
    return 'i';
  }
  else if (m.equals(morse_j)) {
    return 'j';
  }
  else if (m.equals(morse_k)) {
    return 'k';
  }
  else if (m.equals(morse_l)) {
    return 'l';
  }
  else if (m.equals(morse_m)) {
    return 'm';
  }
  else if (m.equals(morse_o)) {
    return 'o';
  }
  else if (m.equals(morse_p)) {
    return 'p';
  }
  else if (m.equals(morse_q)) {
    return 'q';
  }
  else if (m.equals(morse_r)) {
    return 'r';
  }
  else if (m.equals(morse_s)) {
    return 's';
  }
  else if (m.equals(morse_t)) {
    return 't';
  }
  else if (m.equals(morse_u)) {
    return 'u';
  }
  else if (m.equals(morse_v)) {
    return 'v';
  }
  else if (m.equals(morse_w)) {
    return 'w';
  }
  else if (m.equals(morse_x)) {
    return 'x';
  }
  else if (m.equals(morse_y)) {
    return 'y';
  }
  else if (m.equals(morse_z)) {
    return 'z';
  }
  else if (m.equals(" ")) {
    return ' ';
  }
  else {
    return '#';
  }
}

// Here is where I make the code able to translate a string into morse
void printMorse (String s) {
  for ( int i = 0; i < s.length(); i++) {
   String tempVar = char2morse(s.charAt(i));
   Serial.print(tempVar);
   if(addSlash(s, i)){
     Serial.print("/");
    }
  }
}

// Here is where slashes are put into returned morse where appropriate
bool addSlash (String s, int pos) {
  bool retVal = true;
  if (pos == s.length() -1 || s.charAt(pos+1) == ' ' || s.charAt(pos) == ' '){//check next char space or end of string
    retVal = false;
  }
  if(pos < 0){//check previous char space
    retVal = false;
  }
  return retVal;

tldr; The function I've created that is called printMorse is able to encode ASCII characters. I want to create another function that is able to then decode Morse into ASCII. I'm not sure how to do this.

charleston3002:
I made a forum post earlier in regards to some of the issues I've been encountering whilst creating a Morse code encoder/decoder. I've tried to apply the advice I received but I'm making little to no progress.

Essentially, what I am trying to do is take a given string or two of Morse code that might look like this:

char t [] = "−−/−−−/.−.=/... /. −.−./−−−/−../.";

char u[] = "−−/−−−−−−−−−/.−./.../. −.−./−−−/−../.";

Just a couple of hours ago I posted a morse encoder/decoder sketch into this forum:
http://forum.arduino.cc/index.php?topic=363388.msg2506385#msg2506385

The sketch works with input sent from the serial monitor:
If you send ASCII-text ==> you get encoded morse dots and dashes
If you send dots and dashes ==> you get decoded ASCII-text

The only difference from your example is:
In your example a slash '/' is used as a inter-character seperator.
In my example, a space character ' ' is doing the same.

What about that flexible encoder/decoder which I posted?
Give it a try! Comments welcome!

Hey, thanks for the advise! It seems to work, so long as when decoding Morse you input a ' ' before typing any Morse.

However, it seems like the way you have created the library for the morse code is different to how I did it, so I don't quite know how I might apply a similar approach to my own code? I'm sorry if it can be done and I'm just not seeing it, I'm relatively new to Arduino :slight_smile:

charleston3002:
Hey, thanks for the advise! It seems to work, so long as when decoding Morse you input a ' ' before typing any Morse.

No, normally you'd have to do that:

  • either set line ending in the serial monitor to "Newline" or "Carriage Return" or "Both NL&CR"
  • or you send ONE SEPERATING CHAR AFTER the last dot/dash

But anyway: It is a quick hack, the code might contain errors.

With decoding morse, you always have to know where the code of a character ends.
When ending the last decoding without seperating char, it might be as well to send a seperating char before the next code.

If you see a single dot, it might be an E ".", but if a dash follows, it might become an A ".-", so for decoding you must detect the pauses between characters, which should be coded by a seperating char that follows the last dot or dash in the morse code.

charleston3002:
However, it seems like the way you have created the library for the morse code is different to how I did it, so I don't quite know how I might apply a similar approach to my own code?

Yes, code is much different. My code is a bit optimized for small RAM usage. Every morse code for a char is coded within a single byte with my code:

B00010010, // F = ..-.

but in your code an F is coded as:

char morse_f[] = "..-.";

that is 5 bytes (4 bytes string contents and finishing '\0' character

So your program data is using much more RAM than my code. Several times more RAM.

Of course, when changing everything in my example sketch, it would also be possible to write a code that works on the bigger string data structures that you are declaring

But why waste RAM?

jurs:
No, normally you'd have to do that:

  • either set line ending in the serial monitor to "Newline" or "Carriage Return" or "Both NL&CR"
  • or you send ONE SEPERATING CHAR AFTER the last dot/dash

Ah, my bad. I had the serial monitor set to no line ending. Like you said, it works just fine when on Newline.

jurs:
Of course, when changing everything in my example sketch, it would also be possible to write a code that works on the bigger string data structures that you are declaring

But why waste RAM?

Yeah I can see that your code is a lot more RAM efficient. It's just that I found it easier to figure out the code when writing it up my way. Like I said, I'm fairly new to Arduino.

Either way, I prefer the way that you've used single bytes, so I'll try and adapt my code in a similar fashion. Thanks for the help! :slight_smile:

charleston3002:
Yeah I can see that your code is a lot more RAM efficient. It's just that I found it easier to figure out the code when writing it up my way. Like I said, I'm fairly new to Arduino.

Yes, it is easy to figure out a RAM wasting program that doesn't work,
while it may be harder to create a RAM efficient program that does work.

In your code I cannot see exactly why the decoding is not working, this is caused because YOU DID NOT POST FULL CODE of your sketch, at least setup() and loop() functions are missing and the programming logic that shows which function is called when during the receipt of chars from serial and in the decoding process.

Most likely the problem with your code is this, watch out, I further crippled your crippled code to show a possible decoding problem in detail:

...
char morse_e[] = ".";
...
char morse_h[] = "....";
char morse_i[] = "..";
...
char morse_s[] = "...";

//Here is where I convert morse code into regular ASCII characters
char morse2char(String m) {
...
  else if (m.equals(morse_e)) {
    return 'e';
  }
...
  else if (m.equals(morse_h)) {
    return 'h';
  }
  else if (m.equals(morse_i)) {
    return 'i';
  }
...
  else if (m.equals(morse_s)) {
    return 's';
...

Most likely after receiving the first dot ".", you will try to decode this against a valid morse code string, and you find letter 'E'.

But if the user sends ".." (letter 'I') or "..." (letter 'S') or "...." (letter 'H'), your code will never try to decode that, becauser earlier in the decoding process finds that "." is a match for letter 'E', so the code never can detect any matching code that consists of several consecutive dots.

Three dots "..." will decode to three times letter 'E' like "EEE", possibly?

Perhaps is that the mistake you make?

I'm unable to detect that, because of you posted only crippled code which just contained a few declarations and functions, but the complete programming logic IS MISSING, YOU DIDN'T POST THE FULL CODE.