Morse library

Hello,
so here is semi-ready morse library.
please, criticise, judge and make suggestions and improvements.
Morse.h

/*
    Morse code transmitter, version 0.1
    Copyright (C) 2008 Miikka Liukkonen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/



#ifndef Morsee_h
#define Morsee_h

#include "WConstants.h"
#include "binary.h"

typedef struct {
    byte code;    
    byte length;    
  } signal;


class Morsee {
  public:
    Morsee( int pin, int intervail );
    void transmitSign( signal sig );
    void transmitString( char str[], int strlen );
    
    signal letters[26],
           figures[20], 
           spaceBetweenWords, 
           spaceBetweenLetters,
           doubleHyphen,   
           quotationmarks,
           questionMark, 
           commercialAt,    
           startingSignal,  
           endOfWork,   
           wait,         
           invitationToTransmit,             
           error,
           understood;  
           
  private:
     int  _pin;
     int  _dash;
     int  _dot;
};

#endif

first part of Morse.cpp

/*
    Morse code transmitter, version 0.1
    Copyright (C) 2008 Miikka Liukkonen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "Morsee.h"
#include "WConstants.h"
#include "binary.h"
Morsee::Morsee( int pin, int intervail )
{
    _pin  = pin;
    _dot  = intervail;
    _dash = intervail+intervail+intervail;
    pinMode( pin, OUTPUT ); 
    
    // LETTERS 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
  letters[0].code = B01000000; letters[0].length = 2;   
  letters[1].code = B10000000; letters[1].length = 4;   
  letters[2].code = B10100000; letters[2].length = 4;   
  letters[3].code = B10000000; letters[3].length = 3;   
  letters[4].code = B00000000; letters[4].length = 1;    //accented e letters[4].code = B00100000;   letters[4].lenght = 5;
  letters[5].code = B00100000; letters[5].length = 4;   
  letters[6].code = B11000000; letters[6].length = 3;   
  letters[7].code = B00000000; letters[7].length = 4;   
  letters[8].code = B00000000; letters[8].length = 2;   
  letters[9].code = B01110000; letters[9].length = 4;   
  letters[10].code = B10100000 letters[10].length = 3;   
  letters[11].code = B01000000; letters[11].length = 4;   
  letters[12].code = B11000000; letters[12].length = 2;   
  letters[13].code = B10000000; letters[13].length = 2;   
  letters[14].code = B11100000; letters[14].length = 3;   
  letters[15].code = B01100000; letters[15].length = 4;   
  letters[16].code = B11010000; letters[16].length = 4;   
  letters[17].code = B01000000; letters[17].length = 3;   
  letters[18].code = B00000000; letters[18].length = 3;   
  letters[19].code = B10000000; letters[19].length = 1;   
  letters[20].code = B00100000; letters[20].length = 3;   
  letters[21].code = B00010000; letters[21].length = 4;   
  letters[22].code = B01100000; letters[22].length = 3;   
  letters[23].code = B10010000; letters[23].length = 4;   
  letters[24].code = B10110000; letters[24].length = 4;   
  letters[25].code = B11000000; letters[25].length = 4;   
    
    // FIGURES ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 0 :
  figures[0].code = B01111000;  figures[0].length = 6;
  figures[1].code = B10110000;  figures[1].length = 5;
  figures[2].code = B10110100;  figures[2].length = 6;  
  figures[3].code = B10010000;  figures[3].length = 4;    
  figures[4].code = B01010000;  figures[4].length = 5;  
  figures[5].code = B11001100;  figures[5].length = 6;
  figures[6].code = B10000100;  figures[6].length = 6;        
  figures[7].code = B01010100;  figures[7].length = 6;  
  figures[8].code = B10010000;  figures[8].length = 5;     
  figures[9].code = B11111000;  figures[9].length = 5; 
  figures[10].code = B01111000;  figures[10].length = 5;   
  figures[11].code = B00111000;  figures[11].length = 5;   
  figures[12].code = B00011000;  figures[12].length = 5;   
  figures[13].code = B00001000;  figures[13].length = 5;   
  figures[14].code = B00000000;  figures[14].length = 5;   
  figures[15].code = B10000000;  figures[15].length = 5;   
  figures[16].code = B11000000;  figures[16].length = 5;   
  figures[17].code = B11000000;  figures[17].length = 4;   
  figures[18].code = B11110000;  figures[18].length = 5;  
  figures[19].code = B11100000;  figures[19].length = 6;

    // MISCELLANEOUS SIGNS   
    understood.code = B00010000;              understood.length = 5;
    error.code = B00000000;                   error.length = 8;
    invitationToTransmit.code = B10100000;    invitationToTransmit.length = 3;
    wait.code = B01000000;                    wait.length = 5;
    endOfWork.code = B00010100;               endOfWork.length = 6;
    startingSignal.code = B10101000;          startingSignal.length = 5;
    commercialAt.code = B00000000;            commercialAt.length = 6;
    questionMark.code = B00110000;            questionMark.length = 6;
    quotationmarks.code = B01001000;          quotationmarks.length = 6;
    doubleHyphen.code = B10001000;            doubleHyphen.length = 5;
    spaceBetweenLetters.code = B00000000;     spaceBetweenLetters.length = 3;
    spaceBetweenWords.code = B00000000;       spaceBetweenWords.length = 7;
}

and the last part..

void Morsee::transmitSign( signal s )
{
  byte mask = B10000000;
  do
  {
    digitalWrite(_pin, HIGH);
    
    if(s.code & mask) {
      delay(_dash);
    } else {
      delay(_dot);
    }
    
    digitalWrite(_pin, LOW);   
    delay(_dot);
    mask >>= 1;
  }
  while(--s.length > 0);
}
void Morsee::transmitString( char str[], int strlen )
{
  for( int i = 0; i <= strlen; i++ )
  {
    if( str[i] >=  67 && str[i] <= 132 )
    {
      transmitSign( letters[str[i]-67] );
    }
    else if( str[i] >=  141 && str[i] <= 172 )
    {
      transmitSign( letters[str[i]-141] );
    }
    else if( str[i] >= 39 && str[i] <= 58 )
    {
      transmitSign( figures[ str[i] - 39 ] );
    }
    else
    {
      switch( str[i] )
      {
        case '?' :
          transmitSign( questionMark );
          break;
        case '"' :
          transmitSign( quotationmarks );
          break;
        case '@' :
          transmitSign( commercialAt );
          break;
        case '=' :
          transmitSign( doubleHyphen );
          break;
        case ' ' :
          transmitSign( spaceBetweenWords );
          continue;
      }
    }
    transmitSign( spaceBetweenLetters );
  }
}

Looking good.

A few minor points:

you may want to fix the typo in the second member of yr signal type, lenght -> length;

I guess you don't trust users to null terminate the string passed to transmitString ;), otherwise you could dispense with strlen

This is good work. I like what you have done, but I take one exception. The call to Morsee use a variable "intervail" which passes the dot time to the routine. Thus setting the words per minute rate. This number is rather obscure. I would propose that you do the math for the user. As long as you writing the library to make this easy for the user, do the whole job ... This is an output routine, we start up a serial routine by issuing a command like "Serial.begin(9600)" so I would suggest you do the following;

(1) make "intervail" private , initialized to 0

(2) create begin() that gets called in a fashion like "myMorse.begin(wpm)" where wpm is a variable or an actual number of the Morse sending speed in words per minute. Then you do the math and set "intervail"

cheers ... BBR (n1bq)

Another typo in Morse.cpp

figures[7] - incorrect encoding for '8', should be:
figures[17].code = B11100000; figures[17].length = 5;

Cool!

I have a suggestion:

Make the library accept two callbacks. Respectively signalOn, and signalOff functions.

If one wants to signal a morse code with other means than a pin high/low, this will be (one of) the way(s) to go.

Addition to the top of the header:

typedef void (*function)(void);

Two additional private member variables:

function userSignalOn;
function userSignalOff;

2nd constructor:

Morsee( function signalOn, function signalOff, int intervail );

Implementation: (be sure to set them to 0 in the other constructor)

Morsee::Morsee( function signalOn, function signalOff, int intervail ){
  userSignalOn = signalOn;
  userSignalOff = signalOff;
  //set other variables to 0
}

void Morsee::transmitSign( signal s )
{
  byte mask = B10000000;
  do
  {
    if (userSignalOn){
      userSignalOn();
    }else{
      digitalWrite(_pin, HIGH);
    }
    
    if(s.code & mask) {
      delay(_dash);
    } else {
      delay(_dot);
    }
    
    if (userSignalOff){
      userSignalOff();
    }else{
      digitalWrite(_pin, LOW);
    }
    delay(_dot);
    mask >>= 1;
  }
  while(--s.length > 0);
}

Now you could use morse coded signals for literally anything :slight_smile:

[edit]I really like the idea of having a begin(wpm).[/edit]