Logo Search packages:      
Sourcecode: xdemorse version File versions  Download package

decode.c

/*  decode.c
 *
 *  Morse code decoding functions of xdemorse application
 */

/*
 *  xdemorse: An application to decode Morse code signals to text
 *
 *  Copyright (C) 2002  Neoklis Kyriazis
 *
 *  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 2 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:
 *
 *  http://www.gnu.org/copyleft/gpl.txt
 */

#include "xdemorse.h"

/* Speed and squelch spin buttond */
extern GtkSpinButton
  *gbl_speed,
  *gbl_squelch;

static int
  space_elem_cnt = 0, /* Number of space elements processed  */
  space_frag_cnt = 0, /* Number of space fragments processed */
  mark_elem_cnt  = 0, /* Number of mark elements processed   */
  mark_frag_cnt  = 0; /* Number of mark fragments processed  */

/* Runtime config data */
extern rc_data_t rc_data;

/*------------------------------------------------------------------------*/

/*  Get_Character()
 *
 *  Decodes a Morse code character from the
 *  sequence of marks (dits and dahs) and spaces
 */

  char
Get_Character( void )
{
  static int
      mark_cnt  = 0,    /* Count of Mark fragments detected  */
      space_cnt = 0,    /* Count of Space fragments detected */
      context   = 0,    /* What context Morse decoding is in */
      hex_code  = 0x01; /* Hex equivalent of Morse character */


  /* Hex equivalent of Morse code is formed by left-shifting */
  /* 1 or 0 into hex_code. The 0x01 initial value marks the  */
  /* beginning of the bit field, 1 being a dit and 0 a dash. */

  /* Get the level of a fragment from tone detector. A fragment   */
  /* is a small fraction of a morse code element, there are from  */
  /* 10 to 30 frags/element depending on Morse speed (30-10 w.p.m) */
  Get_Fragment();
  if( isFlagSet(DSP_IO_ERROR) )
      return(0);

  /* Increment mark or space count */
  if( isFlagSet(MARK_TONE) )
      mark_cnt++;
  else
      space_cnt++;

  /* If a mark element is too long, limit count */
  if( mark_cnt > rc_data.unit_elem * 8 )
      mark_cnt = rc_data.unit_elem * 8;

  /* If a space element is too long, limit count */
  if( space_cnt > rc_data.unit_elem * 16 )
      space_cnt = rc_data.unit_elem * 16;

  /* Process mark and space element counts to decode Morse */
  switch( context )
  {
      case MARK_SIGNAL: /* Process mark element */

        /* If fragment is a mark */
        if( isFlagSet(MARK_TONE) )
        {
            /* If mark element is too long */
            /* reset and wait for a space  */
            if( mark_cnt >= (rc_data.unit_elem * 8) )
            {
              /* Clear space counter */
              space_cnt = 0;

              /* Clear hex character code */
              hex_code = 0x01;

              /* Wait for a space fragment */
              context = WAIT_FOR_SPACE;

            } /* if( mark_cnt >= rc_data.unit_elem * 8 ) */

        } /* if( isFlagSet(MARK_TONE) ) */
        else
        {
            /* Clear space count to 1 */
            space_cnt = 1;

            /* Switch to processing inter-element space */
            context = ELEM_SPACE;
        }

        break;

      case ELEM_SPACE: /* Process inter-element space */

        /* If space reaches 1/2 units its an inter-element space */
        if( ((space_cnt * 2) >= rc_data.unit_elem) ||
              isFlagSet(MARK_TONE) )
        {
            /* If mark is < 2 units its a dit else a dash */
            if( (mark_cnt < rc_data.unit_elem * 2) )
            {
              /* Insert dit and increment mark frag and elem count */
              hex_code = (hex_code << 1) | 0x01;
              mark_frag_cnt += mark_cnt;
              mark_elem_cnt += 1; /* A dit is 1 element long */
            }
            else
            {
              /* Insert dash and increment mark frag and elem count */
              hex_code <<= 1;
              mark_frag_cnt += mark_cnt;
              mark_elem_cnt += 3; /* A dash is 3 elements long */
            } /* if( mark_cnt < rc_data.unit_elem * 2 ) */

            /* Clear mark count */
            mark_cnt = 0;

            /* Wait for inter-char space count */
            if( isFlagClear(MARK_TONE) )
              context = CHAR_SPACE;
            else
            {
              space_cnt = 0;
              context = MARK_SIGNAL;
            }

        } /* if( (space_cnt * 2) >= rc_data.unit_elem || ) */

        break;

      case CHAR_SPACE: /* Wait for inter-char space */

        /* If fragment is space */
        if( isFlagClear(MARK_TONE) )
        {
            /* If space reaches 2 units its inter-character */
            if( space_cnt >= (rc_data.unit_elem * 2) )
            {
              /* Switch to waiting for inter-word space */
              context = WAIT_WORD_SPACE;

              /* Return decoded Morse char */
              return( Hex_to_Ascii(&hex_code) );
            }

        }  /* if( isFlagClear(MARK_TONE) ) */
        else /* Its the end of inter-element space */
        {
            /* Count up space frags and elements */
            space_frag_cnt += space_cnt;
            space_elem_cnt++; /* Inter-element space */

            /* Clear space cnt and process marks */
            space_cnt = 0;
            context = MARK_SIGNAL;
        }

        break;

      case WAIT_WORD_SPACE: /* Wait for an inter-word space */

        /* If fragment is space */
        if( isFlagClear(MARK_TONE) )
        {
            /* If space count reaches 5, its word space */
            if( space_cnt >= (rc_data.unit_elem * 5) )
              context = WORD_SPACE;

        }  /* if( isFlagClear(MARK_TONE) ) */
        else /* Its the end of inter-character space */
        {
            /* Adapt to incoming signal */
            Adapt_Decoder();

            /* Switch to processing mark signal */
            space_cnt = 0;
            context = MARK_SIGNAL;
        }

        break;

      case WORD_SPACE: /* Process Inter-word space */

        /* If fragment is space */
        if( isFlagClear(MARK_TONE) )
        {
            if( space_cnt >= (rc_data.unit_elem * 7) )
            {
              context = WAIT_FOR_MARK;
              return( ' ' );
            }
        }
        else
        {
            /* Adapt to incoming signal */
            Adapt_Decoder();

            /* Switch to processing mark signal */
            space_cnt = 0;
            context = MARK_SIGNAL;
            return( ' ' );
        }

      case WAIT_FOR_MARK: /* Process no-signal space */

        /* If fragment is mark switch to processing marks */
        if( isFlagSet(MARK_TONE) )
        {
            space_cnt = 0;
            context = MARK_SIGNAL;
        }

        break;

      case WAIT_FOR_SPACE: /* Wait for space after long dash */

        /* If fragment is space, switch to counting space */
        if( isFlagClear(MARK_TONE) )
        {
            space_cnt = 1;
            mark_cnt  = 0;
            context = WAIT_FOR_MARK;
        }

        break;

      default: /* Set context if none */
        if( isFlagSet(MARK_TONE) )
            context = MARK_SIGNAL;
        else
            context = WAIT_FOR_MARK;

  } /* End of switch( context ) */

  return( 0 );

} /* End of Get_Character() */

/*------------------------------------------------------------------------*/

/*  Adapt_Decoder()
 *
 *  Adjusts Morse speed from measurements on the incoming signal
 */

  void
Adapt_Decoder( void )
{
  int
      speed,     /* Morse speed in wpm */
      speed_err; /* Morse speed error  */

  /* Calculate Morse speed */
  if( mark_elem_cnt  &&
        mark_frag_cnt  &&
        space_elem_cnt &&
        space_frag_cnt )
  {
      if( isFlagSet(ADAPT_SPEED) )
      {
        /* Estimate Morse speed from space and mark counts */
        speed_err = (mark_frag_cnt + space_frag_cnt) /
                          (mark_elem_cnt + space_elem_cnt)
                          - rc_data.unit_elem;

        /* Morse speed limits (60-6 wpm) */
        if( (rc_data.unit_elem > rc_data.min_unit) && (speed_err < 0) )
                  rc_data.unit_elem--;
        if( (rc_data.unit_elem < rc_data.max_unit) && (speed_err > 0) )
                  rc_data.unit_elem++;

        /* Display speed in wpm */
        speed = ( 60 * rc_data.tone_freq ) /
            ( 50 * CYCLES_PER_FRAG * rc_data.unit_elem );
        gtk_spin_button_set_value( gbl_speed, (gdouble) speed );

      } /* if( isFlagSet(ADAPT_SPEED) ) */

  } /* if( mark_elem_cnt && space_elem_cnt && space_frag_cnt ) */

  /* Clear counters */
  space_elem_cnt = space_frag_cnt = 0;
  mark_elem_cnt  = mark_frag_cnt  = 0;

} /* Adapt_Decoder() */

/*------------------------------------------------------------------------*/

/*  Hex_to_Ascii()
 *
 *  Converts the hex equivalent of
 *  a Morse code character to ASCII
 */

  char
Hex_to_Ascii( int *hex_code )
{
  /* Table of ASCII characters available in Morse code */
  static char
      morse_ascii_char[ NUMBER_OF_CHAR + 1 ] = MORSE_ASCII_CHAR;

  /* Table of hex equivalent of Morse characters */
  static unsigned char
      morse_hex_char[ NUMBER_OF_CHAR ] = MORSE_HEX_CODE;

  int idx; /* Loop index */

  /* Look for a match in hex table */
  for( idx = 0; idx < NUMBER_OF_CHAR; idx++ )
      if( *hex_code ==  morse_hex_char[ idx ] )
        break;

  /* Clear hex code after conversion */
  *hex_code = 0x01;

  /* Return ascii equivalent of hex code */
  return( morse_ascii_char[ idx ] );

} /* End of Hex_to_Ascii() */

/*------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index