xdemorse-1.3.orig/0000755000175000017500000000000011112236641012427 5ustar pg4ipg4ixdemorse-1.3.orig/AUTHORS0000644000175000017500000000004710620614547013510 0ustar pg4ipg4iNeoklis Kyriazis Ham Radio Call: 5B4AZ xdemorse-1.3.orig/configure.in0000644000175000017500000000116111111453671014742 0ustar pg4ipg4idnl Process this file with autoconf to produce a configure script. AC_INIT(configure.in) AM_INIT_AUTOMAKE(xdemorse, 1.3) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE AC_ISC_POSIX AC_PROG_CC AM_PROG_CC_STDC AC_HEADER_STDC pkg_modules="gtk+-2.0 >= 2.0.0" PKG_CHECK_MODULES(PACKAGE, [$pkg_modules]) AC_SUBST(PACKAGE_CFLAGS) AC_SUBST(PACKAGE_LIBS) GETTEXT_PACKAGE=xdemorse AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package.]) dnl Add the languages which your application supports here. ALL_LINGUAS="" AM_GLIB_GNU_GETTEXT AC_OUTPUT([ Makefile src/Makefile po/Makefile.in ]) xdemorse-1.3.orig/autogen.sh0000755000175000017500000001057410714016655014447 0ustar pg4ipg4i#!/bin/sh # Run this to generate all the initial makefiles, etc. srcdir=`dirname $0` test -z "$srcdir" && srcdir=. DIE=0 if [ -n "$GNOME2_DIR" ]; then ACLOCAL_FLAGS="-I $GNOME2_DIR/share/aclocal $ACLOCAL_FLAGS" LD_LIBRARY_PATH="$GNOME2_DIR/lib:$LD_LIBRARY_PATH" PATH="$GNOME2_DIR/bin:$PATH" export PATH export LD_LIBRARY_PATH fi (test -f $srcdir/configure.in) || { echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" echo " top-level package directory" exit 1 } (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`autoconf' installed." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" DIE=1 } (grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && { (intltoolize --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`intltool' installed." echo "You can get it from:" echo " ftp://ftp.gnome.org/pub/GNOME/" DIE=1 } } (grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && { (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`xml-i18n-toolize' installed." echo "You can get it from:" echo " ftp://ftp.gnome.org/pub/GNOME/" DIE=1 } } (grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { (libtool --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`libtool' installed." echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" DIE=1 } } (grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.in >/dev/null) && { (grep "sed.*POTFILES" $srcdir/configure.in) > /dev/null || \ (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`glib' installed." echo "You can get it from: ftp://ftp.gtk.org/pub/gtk" DIE=1 } } (automake --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`automake' installed." echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" DIE=1 NO_AUTOMAKE=yes } # if no automake, don't bother testing for aclocal test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: Missing \`aclocal'. The version of \`automake'" echo "installed doesn't appear recent enough." echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" DIE=1 } if test "$DIE" -eq 1; then exit 1 fi if test -z "$*"; then echo "**Warning**: I am going to run \`configure' with no arguments." echo "If you wish to pass any to it, please specify them on the" echo \`$0\'" command line." echo fi case $CC in xlc ) am_opt=--include-deps;; esac for coin in `find $srcdir -name configure.in -print` do dr=`dirname $coin` if test -f $dr/NO-AUTO-GEN; then echo skipping $dr -- flagged as no auto-gen else echo processing $dr ( cd $dr aclocalinclude="$ACLOCAL_FLAGS" if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then echo "Creating $dr/aclocal.m4 ..." test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 echo "Running glib-gettextize... Ignore non-fatal messages." echo "no" | glib-gettextize --force --copy echo "Making $dr/aclocal.m4 writable ..." test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 fi if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then echo "Running intltoolize..." intltoolize --copy --force --automake fi if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then echo "Running xml-i18n-toolize..." xml-i18n-toolize --copy --force --automake fi if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then if test -z "$NO_LIBTOOLIZE" ; then echo "Running libtoolize..." libtoolize --force --copy fi fi echo "Running aclocal $aclocalinclude ..." aclocal $aclocalinclude if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then echo "Running autoheader..." autoheader fi echo "Running automake --gnu $am_opt ..." automake --add-missing --gnu $am_opt echo "Running autoconf ..." autoconf ) fi done conf_flags="--enable-maintainer-mode" if test x$NOCONFIGURE = x; then echo Running $srcdir/configure $conf_flags "$@" ... $srcdir/configure $conf_flags "$@" \ && echo Now type \`make\' to compile. || exit 1 else echo Skipping configure process. fi xdemorse-1.3.orig/xdemorse.glade0000644000175000017500000006376111111311621015257 0ustar pg4ipg4i 4 True Xdemorse GTK_WINDOW_TOPLEVEL GTK_WIN_POS_CENTER False False False True False False GDK_WINDOW_TYPE_HINT_NORMAL GDK_GRAVITY_NORTH_WEST True False True False 0 4 True 0 0.5 GTK_SHADOW_ETCHED_IN 4 True True GTK_POLICY_NEVER GTK_POLICY_ALWAYS GTK_SHADOW_IN GTK_CORNER_TOP_LEFT 600 256 True True False False False GTK_JUSTIFY_LEFT GTK_WRAP_WORD True 0 0 0 0 0 0 True False 0 2 True True GTK_RELIEF_NORMAL True False False True 0.5 0.5 0 0 2 2 2 2 True False 2 True gtk-apply 4 0.5 0.5 0 0 0 False False True Receive True False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 0 False False 0 True True 2 True True GTK_RELIEF_NORMAL True True 0.5 0.5 0 0 2 2 2 2 True False 2 True gtk-clear 4 0.5 0.5 0 0 0 False False True Clear window True False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 0 False False 0 True True label_item 0 True True True False 0 4 True 0 0.5 GTK_SHADOW_ETCHED_IN True 0.5 0.5 1 1 2 2 2 2 264 89 True GDK_BUTTON_PRESS_MASK True Scope False False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 label_item 0 True True True False 0 True False 0 4 True 0 0.5 GTK_SHADOW_ETCHED_IN True True 1 0 False GTK_UPDATE_ALWAYS False False 20 10 60 1 10 0 True True Auto wpm True GTK_RELIEF_NORMAL True True False True label_item 0 True True 4 True 0 0.5 GTK_SHADOW_ETCHED_IN True True 1 0 False GTK_UPDATE_ALWAYS False False 50 0 100 1 10 0 True Threshold False False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 label_item 0 True True 0 False False 4 True 0 0.5 GTK_SHADOW_ETCHED_IN True 0.5 0.5 1 1 2 2 2 2 258 89 True GDK_BUTTON_PRESS_MASK True Waterfall False False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 label_item 0 True True 0 True True 0 True True 4 True Xdemorse GTK_WINDOW_TOPLEVEL GTK_WIN_POS_MOUSE True True False True False False GDK_WINDOW_TYPE_HINT_DIALOG GDK_GRAVITY_NORTH_WEST True False True True False 0 True GTK_BUTTONBOX_END 2 True True True gtk-quit True GTK_RELIEF_NORMAL True 0 2 True True True gtk-ok True GTK_RELIEF_NORMAL True -5 0 False True GTK_PACK_END 4 True 0 0.5 GTK_SHADOW_ETCHED_IN True False 0 True gtk-dialog-error 6 0.5 0.5 0 0 0 False False True Generic Error Message pop-up False False GTK_JUSTIFY_LEFT False False 0.5 0.5 4 0 PANGO_ELLIPSIZE_NONE -1 False 0 0 False False True Error! False False GTK_JUSTIFY_LEFT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 label_item 0 True True xdemorse-1.3.orig/doc/0000755000175000017500000000000011112217630013171 5ustar pg4ipg4ixdemorse-1.3.orig/doc/xdemorse.html0000644000175000017500000004034611111451514015714 0ustar pg4ipg4i xdemorse User Manual

xdemorse User Manual

  1. Introduction
  2. Features
  3. Compilation
  4. Command line options
  5. Operation
  6. Bugs and annoyances
  7. Version history
  8. Copying

1. Introduction
xdemorse is a X/GTK+ application for decoding Morse code signals into text. xdemorse detects the "dihs" and "dahs" that make a Morse code character via the computer's sound card, which can be connected to a radio receiver tuned to a CW Morse code transmission or to a tone generator. The input signal is processed by a Goertzel tone detector algorithm which produces "mark" or "space" (signal/no signal) outputs and the resulting stream of Morse code "elements" is decoded into an ASCII character for printing to the Text viewer.

2. Features

Goertzel tone detector
xdemorse was designed from the beginning to be simple and efficient, decoding Morse code using (almost) only integer arithmetic and simple processing methods. It uses the computer's sound card to read the "dit" and "dah" elements that make the Morse coded characters by implementing an integer Goertzel tone detector algorithm, which measures the level of sound signals from a radio receiver or tone generator. This Goertzel tone detector is centered on a nominal frequency of 500 Hz, which is lower than the more common 700-800 Hz BFO setting, because my PSK31 applications have to work with a 500 Hz audio tone due to various limitations. I have chosen to run my Morse decoding applications on the same BFO setting, to avoid regular changes to my receiver.

The Mark/Space (key-down - key-up) condition is detected using an edge detector which give a positive spike for a mark->space transition and a negative spike for a space->mark transition.

Error and noise tolerance
xdemorse has a certain level of tolerance towards operator errors (bad "fist") regarding deviation from the standard duration of the various elements that make up the Morse code. It can also reject to some extend the effects of interference and noise by ignoring marks or spaces shorter than a certain fraction of the unit Morse code element. Below is a table of the basic Morse code elements and the range of durations that xdemorse can deal with:

   Morse Element           Duration       xdemorse
-------------------------------------------------
       dit                  1 units   1/2-2 units
       dah                  3 units     2-4 units
Inter-elem space            1 units   1/2-2 units
Inter-char space            3 units     2-4 units
Inter-word space          > 5 units     > 4 units
 
The Morse code characters, punctuation marks and special signals that xdemorse can currently recognize are in the file doc/Morse-code.txt. Extra characters etc can be added to the collection by inserting the hex equivalent of the decoded Morse code character in the xdemorse.h header file before compilation. Please see detailed explanation in that file.

"Waterfall" display with CAT
xdemorse has a "Waterfall" (audio spectrum) display derived from a FFT of the receiver's audio output. A vertical red line indicates the center frequency of the tone detector. When tuning a signal manually, its trace should be centered on this line for best results. Clicking with the center button on the display reverses the background/foreground colors of the display.

xdemorse has built-in CAT capability but only for the Yaesu FT847 or FT857, the only rigs I have. This is an unfortunate limitation but an attempt to convert xdemorse to using the "hamlib" library was unsuccessful for various reasons. The waterfall display can be used to tune in a signal by clicking with the left mouse button near its trace. xdemorse will scan a small section of the display either side of the mouse pointer, looking for the strongest trace and then tune the receiver so that the signal is centered on the red line. Since the FT847/FT857 has only a 10 Hz resolution when tuned by the CAT, there can be an error of +-5 Hz in the tuning of a signal. Other errors resulting from the finite resolution of the FFT can increase the tuning discrepancy and since xdemorse has a sharp tone detector, it may be necessary to fine-tune the receiver manually for best results.

Sound-card set-up
xdemorse automatically sets up the sound card and tries to set the input and recording/capture level to the RECORD_LEV entry in xdemorse.h. If it fails it will give an appropriate warning and the mixer levels for line input and recording level must be set up manually using a mixer app like 'aumix'.

For proper operation the level of the input audio signal must be adjusted from the receiver or the tone generator, using the 'scope' display at the bottom left of the main window. If the audio signal is taken from an outlet that provides a fixed audio level, then the #define RECORD_LEV entry in xdemorse.h will need to be edited by trial and error and xdemorse re-compiled, until the signal plotted in the scope display is about 80% of the height of the scope frame.

3. Compilation
Please note that I use Arch Linux AMD64 which is a "bleeding edge" type distribution, so there may be compilation and/or run time difficulties if you are using a relatively old distro. This is mostly true of the basic dependencies like GTK+ 2 and Glade-2, and there can also be sound card incompatibility problems at run time.

To compile the package the first time, run the "autogen.sh" script in the package's top directory. The "configure" script as produced by Glade-2 specifies the gcc flags as "-g -O2", but if you want to specify different flags, you will have to run "configure" with the CFLAGS option, e.g. ./configure CFLAGS="-Wall -O2 -march=i686" or whatever flags of your choice.

Run "make" to produce the executable binary "xdemorse" in src/. This can then be copied to a suitable location, usually /usr/local/bin or /usr/bin. You can of course run "make install" which will install the binary into /usr/local/bin by default. You can change this to a different location, e.g. /usr/bin, by including the --prefix=/usr option when running "configure". To recompile the package, you must run "make distclean" in the top directory to clean up the package and then run the "configure" script and "make install".

There is this hypertext documentation file which you can copy to a location of your choice. There is also a default configuration file .xdemorserc in the 'default" subdirectory. This must be copied to your home directory and edited to match your setup. If you have problems identifying your sound card mixer devices (recording source, recording level etc) run "xdemorse -l" in a terminal to get a list of mixer device names.

4. Command line options:

xdemorse [-hlv]
-h: Print this usage information and exit.
-l: List mixer device names and exit.
-v: Print version number and exit.

5. Operation
Before xdemorse is used to decode Morse signals, the input level to the sound card must be set up correctly. For this, the radio receiver or tone generator must be connected to the "line" input of the sound card with a suitable cable and connectors, with either the left or right channel connected to the receiver's o/p if in stereo mode, or if in mono mode normally the left channel input. The receiver's output level is adjusted so that the maximum signal input level, as shown in the 'scope' display at the bottom left of the main window, is about 80% of the scope's window height. The receiver should be tuned to a strong, clean CW transmission, with the AGC setting in the fast position and IF/AF bandwidth in the narrowest setting. Please note that the receiver should be tuned accurately to the incoming signal so that the BFO note is 500Hz. This can be done by slowly tuning the receiver, with a tuning step of 1Hz if available, so that the INPUT SIGNAL display in the scope is at a maximum. The waterfall display is also very useful for tuning, since a signal trace tuned to be exactly under the red middle line of the waterfall will result in a 500 Hz BFO frequency.

By default xdemorse starts with Morse code speed set to 20 wpm and the detector threshold set at 50. These are shown in the two spin-wheel widgets at the right of the scope window. As xdemorse begins to decode Morse coded signals, it estimates the sending speed and adapts to it, indicating the actual speed in the 'Speed' spin-wheel. If the Morse transmission is a lot faster or slower than the indicated speed, it may not be decoded correctly and manual changing of the speed setting will be needed to fix the problem. Auto adaptation to incoming Morse speed can be disabled with the "Auto wpm" check button.

To decode Morse code from a communications receiver, set the BFO so that the tone of the CW signal is near to 500 Hz and then start xdemorse. Assuming that keying is not too bad (operator's 'fist' is reasonably good) then decoded characters should appear in the 'Receive Window' of xdemorse. Some changes to the speed and/or squelch setting may be helpful and experience will show the best setting for the latter. A maximum tuning step of 1 Hz should be selected on digital receivers and tuning should be slow. A narrow CW filter is an advantage although very narrow (less than 300-400 Hz) IF or dsp/AF filters tend to ring and cause spurious characters, mainly E's to be printed on the screen.

Please note that the 'scope' display of xdemorse-fft has two functions, it can display the input signal waveform or the output from the Mark/Space (signal/no-signal) detector. The first function is the default and it can be selected, stopped or started by clicking in the scope window with the left button of the mouse. The second function can be selected, stopped or started by clicking in the scope window with the right button of the mouse. The middle button stops whatever function is selected. Clicking on the FFT display with the middle button reverses background/foreground colors.

Generally xdemorse has a fairly wide tolerance of sending errors (bad fists or noise) but in practice it has proved to be difficult to correctly decode CW signals on the amateur bands, with the main problem appearing to be bad keying habits. Sometimes inter-character spacing is too small so two or more characters are taken as one and therefore cannot be decoded correctly. Characters not recognized by xdemorse are indicated by an asterisk * on the screen. Word spacing also seems to be inconsistent with many hams resulting in fragmented or fused words.

Finally a list of all characters, punctuation marks and special signals recognized by xdemorse are listed in the doc/Morse-code.txt file. Additional characters can be entered in two tables in the xdemorse.h header file before compilation, following the instructions in there.

6. Bugs and annoyances
I have fixed whatever bugs I came across testing xdemorse but there may be some hiding, waiting for the right conditions to appear.

The Morse code decoding algorithm may need further improvements to make it more tolerant to errors and noise and the mark/space detection process may need to be improved to reduce spurious output due to noise interference.

7. Version history

Version 0.1: First beta release of this basic Morse decoding X/GTK+ application, which is based on the console Morse decoding tool 'demorse'.

Version 0.2: Added a simple "Oscilloscope" display of the incoming waveform or the Detector output.

Version 0.3: Added a simple FFT-based "Waterfall" display of the receiver's audio spectrum. The Waterfall display incorporates CAT functions for the FT847 or FT857 transceiver allowing netting of the receiver by clicking on the trace of a signal.

Version 0.4: Replaced the original software synchronous tone detector with a Goertzel tone detector, since it has slightly better performance.

Version 0.5: Changed Mark/Space tone detection from thresholding the signal level to detecting the mark->space and space->mark transition edge. Seems to give more reliable decoding.

Version 0.6: Added a display function for the output of the Goertzel signal detector. This is displayed int the "scope" window at the left lower corner of the xdemorse window.

Version 0.7: Changed the detector scheme to a Mark/Space transition (edge) detector which works by counting the number of consecutive signal samples (steps) that change by more than 5% in the same direction (up or down). If the number of steps is more than a given threshold (default 60% of the Morse element duration) then this is taken to indicate a rising or falling edge. This seems to work better than the previous slope detection scheme. Also added a few extra command line options to specify parameters for demorse's operation.

Version 0.8 Added a parser to read a runtime configuration file from the user's home directory. This file (~/.xdemorse) must be edited to match the user's setup. The command line options for specifying the various parameters xdemorse needs have been removed. Also its no longer necessary to make any changes to the xdemorse.h header.

Version 0.9 After a bug report from Juha Vierinen regarding seg faulting of xnec2c, my graphical adaptation of NEC2, I changed all "sprintf" commands to "snprintf" to avoid buffer overruns. Following on the above changes, I revised all similar situations in xdemorse source code and changed all "sprintf" commands to "snprintf" just in case. While going through the xdemorse source code, I also fixed some minor bugs like typos and tidied error messages and other aspects of the GUI.

Version 1.0 After a bug report from Pino Zollo ZP4KFX, I modified the waterfall display function to avoid a divide by zero condition that caused a SIGFPE crash.

Version 1.1 After a bug report from Pino Zollo ZP4KFX regarding GUI problems with my Hellschreiber program xfhell, I made some changes to the GUI code in most of my GTK2 applications.

Version 1.2 After a bug report from Pino Zollo ZP4KFX, regarding failure of "xdemorse" to start the Morse decoding loop after reading its configuration file, I have modified the functions that read this file so that more detailed error messages are printed if entries are malformed.
I added 3 new entries to the ~/.xdemorserc config file to allow a wider range of max and min Morse speeds and to define the initial Morse speed (WPM) at start-up. I also added a "Receive" button in the GUI to start and stop xdemorse as needed.

Version 1.3 Made the page size of spin buttons 0 to make setting of spin button values compatible with GTK 2.4.

8. Copying This software package is released under the GNU Public License. Please see the COPYING file for more details.

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:

August 16 2002.

Last modified: Mon Mar 31 16:13:49 EEST 2003

xdemorse-1.3.orig/doc/Morsecode.txt0000644000175000017500000000715510767763033015704 0ustar pg4ipg4i MORSE CODE Alphabet Letter Composed of: Sounds Like Letter Composed of: Sounds Like A . _ didah N _ . dahdit B _ . . . dahdididit O _ _ _ dahdahdah C _ . _ . dahdidahdit P . _ _ . didahdahdit D _ . . dahdidit Q _ _ . _ dahdahdidah E . dit R . _ . didahdit F . . _ . dididahdit S . . . dididit G _ _ . dahdahdit T _ dah H . . . . didididit U . . _ dididah I . . didit V . . . _ didididah J . _ _ _ didahdahdah W . _ _ didahdah K _ . _ dahdidah X _ . . _ dahdididah L . _ . . didahdidit Y _ . _ _ dahdidahdah M _ _ dahdah Z _ _ . . dahdahdidit ________________________________________________________________________________ Numerals Number Composed of: Sounds Like 1 . _ _ _ _ didahdahdahdah 2 . . _ _ _ dididahdahdah 3 . . . _ _ didididahdah 4 . . . . _ dididididah 5 . . . . . dididididit 6 _ . . . . dahdidididit 7 _ _ . . . dahdahdididit 8 _ _ _ . . dahdahdahdidit 9 _ _ _ _ . dahdahdahdahdit 0 _ _ _ _ _ dahdahdahdahdah ________________________________________________________________________________ Punctuation Character Composed of: Sounds Like Period . . _ . _ . _ didahdidahdidah Comma , _ _ . . _ _ dahdahdididahdah Colon : _ _ _ . . . dahdahdahdididit Question mark ? . . _ _ . . dididahdahdidit Apostrophe ' . _ _ _ _ . didahdahdahdahdit Hyphen - _ . . . . _ dahdididididah Fraction bar / _ . . _ . dahdididahdit Parentheses ( ) _ . _ _ . _ dahdidahdahdidah Quotation marks " . _ . . _ . didahdididahdit Semicolon ; _ . _ . _ . dahdidahdidahdit Dollar sign $ . . . _ . . _ didididahdididah _______________________________________________________________________________ Special Signals Character Symbol Composed of: Sounds Like End of message (AR) # . _ . _ . didahdidahdit End of Work (VA) < . . . _ . _ didididahdidah Attention ! _ . _ . _ dahdidahdidah Wait sign (AS) @ . _ . . . didahdididi Selective call (KN) ] _ . _ _ . dahditdahdahdit Break = _ . . . _ dahditditditdah Invitation to transmit (K) _ . _ dahdidah Test letter (V) . . . _ didididah Received, ok (R) . _ . didahdit Error ~ . . . . . . . . didididididididit _______________________________________________________________________________ xdemorse-1.3.orig/default/0000755000175000017500000000000011003604177014055 5ustar pg4ipg4ixdemorse-1.3.orig/default/.xdemorserc0000644000175000017500000000743510772460231016245 0ustar pg4ipg4i########### xdemorse RUNTIME CONFIGURATION FILE: xdemorserc ######### # # # PLEASE NOTE! In order to keep the parser for this file simple, # # the runtime configuration entries below must all be present and # # in the order presented, since they are all read-in in a fixed # # sequence. Blank lines or those starting with a # or white space # # are ignored. # # # ##################################################################### # ####### SOUND-CARD CONFIGURATION ####### # # Please look in /usr/include/soundcard.h # (search for SOUND_DEVICE_NAMES) to find valid device names. # # Mixer device: Default is /dev/mixer /dev/mixer # # Capture DSP device: Default is /dev/dsp /dev/dsp # # The sampling speed of the sound card's DSP. This should as # far as possible be the native speed of the DSP to avoid # resampling, as it seems resampling distorts the signal. 48000 # # Audio capture/recording source: Default is line. # Alternative is usually mic or line1 etc. line # # Audio recording level device: Default is igain. # Alternative is usually reclev or rec. igain # # Recording/Capture level: Useful range ~10-100. Default is 64. # The correct value must be found by testing, see xdemorse.html. 64 # # Sound card mode: (STEREO | MONO). My default is STEREO because # I have two sources (receivers) connected to the sound card. STEREO # # Channel in use by xdemorse: (LEFT | RIGHT). My default is RIGHT. # When in MONO mode, this field is ignored. On my system at # least, only the left channel works in MONO. RIGHT # ####### End of SOUND-CARD CONFIGURATION ####### # ####### xdemorse RUNTIME CONFIGURATION ####### # # Maximum Morse speed to decode. xdemorse is internally limited to # the range 6-60 Words per Minute, but you might want to limit the # maximum speed to a lower value, as this also reduces susceptibility # to radio noise which can "drag" the current WPM to high values, if # Auto speed detection and tracking is enabled. Default is 40 wpm 40 # # Minimum Morse speed to decode. xdemorse is internally limited to # the range 6-60 Words per Minute, but you might want to limit the # minimum speed since a very low setting can "lock" the Auto speed # detection and tracking to this low value. Default is 10 wpm 10 # # Initial Morse decoding speed WPM. Should be between above limits! 20 # # Word-wrap line length. Default is 60 55 # # Serial port device for FT847 CAT: Default is /dev/tts/0 # IN MY SETUP! Please specify the serial port device you # intend to use for CAT control of your tranceiver. PLEASE NOTE: # CAT is available only for the YAESU FT-847 and FT857 which I own. # If you are using some other tranceiver, there is no need to edit # these entries BUT DO NOT ACTIVATE CAT as xfhell WILL ABORT! /dev/tts/2 # # Serial port device for FT857 CAT: Default is /dev/tts/1 # IN MY SETUP! Please specify the serial port device you # intend to use for CAT control of your tranceiver. PLEASE NOTE: # CAT is available only for the YAESU FT-847 and FT857 which I own. # If you are using some other tranceiver, there is no need to edit # these entries BUT DO NOT ACTIVATE CAT as xfhell WILL ABORT! /dev/tts/0 # # Enable CAT for Yaesu FT847 OR FT857 transceivers. # Setting is FT847 or FT857 or NONE if you have some # other transceiver or don't want CAT. FT847 # # BFO Tone frequency. This is the frequency of the receiver's # audio output when a CW signal is tuned in the center of the # IF passband. Because xdemorse uses integer arithmatic to # detect the signal and to display the waterfall (by using # an integer FFT algorithm), this value will be rounded # in xdemorse to a value that keeps the above functions at # a reasonable accuracy. 500 # xdemorse-1.3.orig/README0000644000175000017500000000006210713316544013314 0ustar pg4ipg4iPlease read the user manual in the doc/ directory xdemorse-1.3.orig/ChangeLog0000644000175000017500000000006210713316544014206 0ustar pg4ipg4iPlease read the user manual in the doc/ directory xdemorse-1.3.orig/po/0000755000175000017500000000000011111453775013055 5ustar pg4ipg4ixdemorse-1.3.orig/po/POTFILES.in0000644000175000017500000000016210714016655014631 0ustar pg4ipg4i# List of source files containing translatable strings. src/main.c src/interface.c src/callbacks.c src/support.c xdemorse-1.3.orig/po/Makefile.in.in0000644000175000017500000001772411111453703015531 0ustar pg4ipg4i# Makefile for program source directory in GNU NLS utilities package. # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper # # This file file be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU Public License # but which still want to provide support for the GNU gettext functionality. # Please note that the actual code is *not* freely available. # # - Modified by Owen Taylor to use GETTEXT_PACKAGE # instead of PACKAGE and to look for po2tbl in ./ not in intl/ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ SHELL = /bin/sh @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ libdir = @libdir@ localedir = $(libdir)/locale gnulocaledir = $(datadir)/locale gettextsrcdir = $(datadir)/glib-2.0/gettext/po subdir = po INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ MKINSTALLDIRS = $(top_srcdir)/@MKINSTALLDIRS@ CC = @CC@ GENCAT = @GENCAT@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ XGETTEXT = @XGETTEXT@ MSGMERGE = msgmerge DEFS = @DEFS@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ INCLUDES = -I.. -I$(top_srcdir)/intl COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) SOURCES = POFILES = @POFILES@ GMOFILES = @GMOFILES@ DISTFILES = LINGUAS ChangeLog Makefile.in.in POTFILES.in $(GETTEXT_PACKAGE).pot \ $(POFILES) $(GMOFILES) $(SOURCES) POTFILES = \ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ INSTOBJEXT = @INSTOBJEXT@ .SUFFIXES: .SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat .c.o: $(COMPILE) $< .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot $(MSGMERGE) $< $(srcdir)/$(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(MSGFMT) -o $@ $< .po.gmo: file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \ && rm -f $$file && $(GMSGFMT) $(MSGFMT_OPTS) -o $$file $< .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ && rm -f $@ && $(GENCAT) $@ $*.msg all: all-@USE_NLS@ all-yes: $(CATALOGS) all-no: $(srcdir)/$(GETTEXT_PACKAGE).pot: $(POTFILES) $(XGETTEXT) --default-domain=$(GETTEXT_PACKAGE) --directory=$(top_srcdir) \ --add-comments --keyword=_ --keyword=N_ \ --flag=g_strdup_printf:1:c-format \ --flag=g_string_printf:2:c-format \ --flag=g_string_append_printf:2:c-format \ --flag=g_error_new:3:c-format \ --flag=g_set_error:4:c-format \ --flag=g_markup_printf_escaped:1:c-format \ --flag=g_log:3:c-format \ --flag=g_print:1:c-format \ --flag=g_printerr:1:c-format \ --flag=g_printf:1:c-format \ --flag=g_fprintf:2:c-format \ --flag=g_sprintf:2:c-format \ --flag=g_snprintf:3:c-format \ --flag=g_scanner_error:2:c-format \ --flag=g_scanner_warn:2:c-format \ --files-from=$(srcdir)/POTFILES.in \ && test ! -f $(GETTEXT_PACKAGE).po \ || ( rm -f $(srcdir)/$(GETTEXT_PACKAGE).pot \ && mv $(GETTEXT_PACKAGE).po $(srcdir)/$(GETTEXT_PACKAGE).pot ) install: install-exec install-data install-exec: install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all if test -r "$(MKINSTALLDIRS)"; then \ $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \ else \ $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \ fi @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ case "$$cat" in \ *.gmo) destdir=$(gnulocaledir);; \ *) destdir=$(localedir);; \ esac; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \ if test -r "$(MKINSTALLDIRS)"; then \ $(MKINSTALLDIRS) $$dir; \ else \ $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \ fi; \ if test -r $$cat; then \ $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ else \ $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ echo "installing $(srcdir)/$$cat as" \ "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ fi; \ if test -r $$cat.m; then \ $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ if test -r $(srcdir)/$$cat.m ; then \ $(INSTALL_DATA) $(srcdir)/$$cat.m \ $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ echo "installing $(srcdir)/$$cat as" \ "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ true; \ fi; \ fi; \ done if test "$(PACKAGE)" = "glib"; then \ if test -r "$(MKINSTALLDIRS)"; then \ $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \ else \ $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \ fi; \ $(INSTALL_DATA) $(srcdir)/Makefile.in.in \ $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ else \ : ; \ fi # Define this as empty until I found a useful application. installcheck: uninstall: catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ done if test "$(PACKAGE)" = "glib"; then \ rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ fi check: all dvi info tags TAGS ID: mostlyclean: rm -f core core.* *.pox $(GETTEXT_PACKAGE).po *.old.po cat-id-tbl.tmp rm -fr *.o clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f $(GMOFILES) distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir) dist distdir: update-po $(DISTFILES) dists="$(DISTFILES)"; \ for file in $$dists; do \ ln $(srcdir)/$$file $(distdir) 2> /dev/null \ || cp -p $(srcdir)/$$file $(distdir); \ done update-po: Makefile $(MAKE) $(GETTEXT_PACKAGE).pot tmpdir=`pwd`; \ cd $(srcdir); \ catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ echo "$$lang:"; \ if $(MSGMERGE) $$lang.po $(GETTEXT_PACKAGE).pot -o $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$cat failed!"; \ rm -f $$tmpdir/$$lang.new.po; \ fi; \ done # POTFILES is created from POTFILES.in by stripping comments, empty lines # and Intltool tags (enclosed in square brackets), and appending a full # relative path to them POTFILES: POTFILES.in ( if test 'x$(srcdir)' != 'x.'; then \ posrcprefix='$(top_srcdir)/'; \ else \ posrcprefix="../"; \ fi; \ rm -f $@-t $@ \ && (sed -e '/^#/d' \ -e "s/^\[.*\] +//" \ -e '/^[ ]*$$/d' \ -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \ | sed -e '$$s/\\$$//') > $@-t \ && chmod a-w $@-t \ && mv $@-t $@ ) Makefile: Makefile.in.in ../config.status POTFILES cd .. \ && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ $(SHELL) ./config.status # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: xdemorse-1.3.orig/po/ChangeLog0000644000175000017500000000000010714016655014615 0ustar pg4ipg4ixdemorse-1.3.orig/NEWS0000644000175000017500000000003010713301303013111 0ustar pg4ipg4iNo news - good news ;-) xdemorse-1.3.orig/Makefile.am0000644000175000017500000000121010714016655014465 0ustar pg4ipg4i## Process this file with automake to produce Makefile.in SUBDIRS = src po EXTRA_DIST = \ autogen.sh \ xdemorse.glade \ xdemorse.gladep install-data-local: @$(NORMAL_INSTALL) if test -d $(srcdir)/pixmaps; then \ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/pixmaps; \ for pixmap in $(srcdir)/pixmaps/*; do \ if test -f $$pixmap; then \ $(INSTALL_DATA) $$pixmap $(DESTDIR)$(pkgdatadir)/pixmaps; \ fi \ done \ fi dist-hook: if test -d pixmaps; then \ mkdir $(distdir)/pixmaps; \ for pixmap in pixmaps/*; do \ if test -f $$pixmap; then \ cp -p $$pixmap $(distdir)/pixmaps; \ fi \ done \ fi xdemorse-1.3.orig/src/0000755000175000017500000000000011112236652013220 5ustar pg4ipg4ixdemorse-1.3.orig/src/display.c0000644000175000017500000001616710772442133015050 0ustar pg4ipg4i/* display.c * * Display functions for 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" /* Signal scope */ extern GtkWidget *gbl_waterfall, *gbl_scope; /* Unit element as fragments/element */ extern int unit_elem; /* fft in/out buffers */ extern int *fft_in_r, *fft_out_r, *fft_out_i; /* Average bin values */ int gbl_bin_ave[FFT_SIZE/2]; /* Waterfall window pixbuf */ extern GdkPixbuf *gbl_wfall_pixbuf; extern guchar *gbl_wfall_pixels; extern gint gbl_wfall_rowstride, gbl_wfall_n_channels, gbl_wfall_width, gbl_wfall_height; /* Runtime config data */ extern rc_data_t rc_data; /*------------------------------------------------------------------------*/ /* Display_Detector() * * Updates the Detector scope display */ void Display_Detector( int plot ) { /* Points to plot */ static GdkPoint points[256]; static int points_idx = 0; int temp; /* Save values to be plotted */ points[points_idx].y = 87 - plot; if( points[points_idx].y < 3 ) points[points_idx].y = 3; if( points[points_idx].y > 87 ) points[points_idx].y = 87; points[points_idx].x = points_idx+3; /* Recycle buffer idx when full and plot */ if( ++points_idx == 256 ) { /* Draw scope background */ gdk_draw_rectangle( gbl_scope->window, gbl_scope->style->white_gc, TRUE, 4, 3, 255, 85 ); /* Draw scope frame */ gdk_draw_rectangle( gbl_scope->window, gbl_scope->style->black_gc, FALSE, 3, 2, 256, 86 ); /* Plot signal graph */ gdk_draw_lines( gbl_scope->window, gbl_scope->style->black_gc, points, 256 ); points_idx = 0; /* Draw Mark/Space threshold references */ temp = 87 - (84*rc_data.det_thr)/100; gdk_draw_line( gbl_scope->window, gbl_scope->style->black_gc, 3, temp, 258, temp ); } /* if( ++points_idx == 256 ) */ } /* Display_Detector() */ /*------------------------------------------------------------------------*/ /* Display_Signal() * * Updates the Signal scope display */ void Display_Signal( int plot ) { /* Points to plot */ static GdkPoint points[256]; static int points_idx = 0; /* Save values to be plotted (SCALED) */ points[points_idx].y = 86 - plot/64; if( points[points_idx].y < 3 ) points[points_idx].y = 3; points[points_idx].x = points_idx+3; /* Recycle buffer idx when full and plot */ if( ++points_idx == 256 ) { /* Draw scope background */ gdk_draw_rectangle( gbl_scope->window, gbl_scope->style->white_gc, TRUE, 4, 3, 255, 85 ); /* Draw scope frame */ gdk_draw_rectangle( gbl_scope->window, gbl_scope->style->black_gc, FALSE, 3, 2, 256, 86 ); /* Plot signal graph */ gdk_draw_lines( gbl_scope->window, gbl_scope->style->black_gc, points, 256 ); points_idx = 0; } /* if( ++points_idx == DRAWABLE_LEN ) */ } /* Display_Signal */ /*------------------------------------------------------------------------*/ /* Display_Waterfall() * * Displays audio spectrum as "waterfall" */ void Display_Waterfall(void) { int idh, idv, /* Index to hor. and vert. position in warterfall */ pixel_val, /* Greyscale value of pixel derived from fft o/p */ fft_idx; /* Index to fft output array */ /* Constant needed to draw red line in waterfall */ static int red_line = WFALL_WIDTH/2; int bin_val, /* Value of fft output "bin" */ bin_max; /* Maximum value of fft bins */ /* Sliding window average of bin max values */ static int ave_max = 1000; /* Pointer to current pixel */ static guchar *pix; /* Draw a vertical red line in waterfall at detector's freq. */ pix = gbl_wfall_pixels + gbl_wfall_rowstride + gbl_wfall_n_channels; pix += gbl_wfall_n_channels * red_line; pix[0] = 0xff; pix[1] = pix[2] = 0; /* Copy each line of waterfall to next one */ for( idv = gbl_wfall_height-2; idv > 0; idv-- ) { pix = gbl_wfall_pixels + gbl_wfall_rowstride * idv + gbl_wfall_n_channels; for( idh = 0; idh < WFALL_WIDTH; idh++ ) { pix[0] = pix[ -gbl_wfall_rowstride]; pix[1] = pix[1-gbl_wfall_rowstride]; pix[2] = pix[2-gbl_wfall_rowstride]; pix += gbl_wfall_n_channels; } } /* Got to top left +1 hor. +1 vert. of pixbuf */ pix = gbl_wfall_pixels + gbl_wfall_rowstride + gbl_wfall_n_channels; /* First column of display (DC) not used */ gbl_bin_ave[0] = 0; /* Do the FFT on input array */ Ifft( FFT_SIZE ); bin_max = 0; for( fft_idx = 0; fft_idx < FFT_SIZE/2; fft_idx++ ) { /* Calculate signal power at each frequency (bin) */ fft_out_r[fft_idx] /=8; fft_out_i[fft_idx] /=8; bin_val = fft_out_r[fft_idx]*fft_out_r[fft_idx] + fft_out_i[fft_idx]*fft_out_i[fft_idx]; /* Calculate average bin values */ gbl_bin_ave[fft_idx] = ( (gbl_bin_ave[fft_idx] * (BINMAX_AVE_WIN-1) + bin_val) / BINMAX_AVE_WIN ); /* Record max bin value */ if( bin_max < bin_val ) bin_max = bin_val; /* Scale pixel values to 255 depending on ave max value */ pixel_val = (255 * bin_val) / ave_max; if( pixel_val > 255 ) pixel_val = 255; int lim = (2*WFALL_WIDTH)/FFT_SIZE; /* Duplicate pixels if fft size < waterfall width */ for( idh = 0; idh < lim; idh++ ) { /* Reverse video is toggled by right click on waterfall */ if( isFlagSet(REVERSE_VIDEO) ) pix[0] = pix[1] = pix[2] = pixel_val; else pix[0] = pix[1] = pix[2] = 255 - pixel_val; pix += gbl_wfall_n_channels; } } /* for( fft_idx = 0; fft_idx < fft_end; fft_idx++ ) */ /* Calculate sliding window average of max bin value */ ave_max = (ave_max*(BINMAX_AVE_WIN-1) + bin_max)/BINMAX_AVE_WIN; if( !ave_max ) ave_max = 1; /* At last draw waterfall */ gtk_widget_queue_draw( gbl_waterfall ); } /* Display_Waterfall() */ /*------------------------------------------------------------------------*/ /* Clear_Pixbuf() * * Initializes pixbuf of Waterfall window */ void Clear_Pixbuf( void ) { int i; guchar *p1, *p2; gdk_pixbuf_fill( gbl_wfall_pixbuf, 0xffffffff ); /* Draw a box around pixbuf */ p1 = gbl_wfall_pixels; p2 = gbl_wfall_pixels + (gbl_wfall_height-1)*gbl_wfall_rowstride; for( i = 0; i < gbl_wfall_width; i++ ) { p1[0] = p1[1] = p1[2] = 0; p1 += gbl_wfall_n_channels; p2[0] = p2[1] = p2[2] = 0; p2 += gbl_wfall_n_channels; } p1 = gbl_wfall_pixels+gbl_wfall_rowstride; p2 = gbl_wfall_pixels+gbl_wfall_rowstride + (gbl_wfall_width-1)*gbl_wfall_n_channels; for( i = 0; i < gbl_wfall_height-1; i++ ) { p1[0] = p1[1] = p1[2] = 0; p1 += gbl_wfall_rowstride; p2[0] = p2[1] = p2[2] = 0; p2 += gbl_wfall_rowstride; } gtk_widget_queue_draw( gbl_waterfall ); } /* Clear_Pixbuf() */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/callbacks.h0000644000175000017500000000530410772753512015324 0ustar pg4ipg4i#include void on_main_window_destroy (GtkObject *object, gpointer user_data); gboolean on_main_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); void on_clear_clicked (GtkButton *button, gpointer user_data); gboolean on_scope_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); gboolean on_scope_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); void on_speed_changed (GtkEditable *editable, gpointer user_data); void on_wpm_toggled (GtkToggleButton *togglebutton, gpointer user_data); void on_squelch_changed (GtkEditable *editable, gpointer user_data); gboolean on_waterfall_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); gboolean on_waterfall_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); void on_err_quit_clicked (GtkButton *button, gpointer user_data); void on_err_ok_button_clicked (GtkButton *button, gpointer user_data); void on_error_dialog_destroy (GtkObject *object, gpointer user_data); gboolean on_error_dialog_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); void on_waterfall_size_allocate (GtkWidget *widget, GdkRectangle *allocation, gpointer user_data); void on_rx_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); xdemorse-1.3.orig/src/interface.c0000644000175000017500000003562311111311621015322 0ustar pg4ipg4i/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "callbacks.h" #include "interface.h" #include "support.h" #define GLADE_HOOKUP_OBJECT(component,widget,name) \ g_object_set_data_full (G_OBJECT (component), name, \ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ g_object_set_data (G_OBJECT (component), name, widget) GtkWidget* create_main_window (void) { GtkWidget *main_window; GtkWidget *vbox1; GtkWidget *frame2; GtkWidget *rx_scrolledwindow; GtkWidget *rx_textview; GtkWidget *hbox4; GtkWidget *rx_togglebutton; GtkWidget *alignment3; GtkWidget *hbox5; GtkWidget *image2; GtkWidget *label9; GtkWidget *clear; GtkWidget *alignment4; GtkWidget *hbox6; GtkWidget *image3; GtkWidget *label10; GtkWidget *hbox1; GtkWidget *frame1; GtkWidget *alignment2; GtkWidget *scope; GtkWidget *label1; GtkWidget *hbox2; GtkWidget *vbox2; GtkWidget *frame4; GtkObject *speed_adj; GtkWidget *speed; GtkWidget *wpm; GtkWidget *frame5; GtkObject *squelch_adj; GtkWidget *squelch; GtkWidget *label8; GtkWidget *frame7; GtkWidget *alignment1; GtkWidget *waterfall; GtkWidget *label7; main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (main_window), 4); gtk_window_set_title (GTK_WINDOW (main_window), _("Xdemorse")); gtk_window_set_position (GTK_WINDOW (main_window), GTK_WIN_POS_CENTER); gtk_window_set_resizable (GTK_WINDOW (main_window), FALSE); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (main_window), vbox1); frame2 = gtk_frame_new (NULL); gtk_widget_show (frame2); gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame2), 4); rx_scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (rx_scrolledwindow); gtk_container_add (GTK_CONTAINER (frame2), rx_scrolledwindow); gtk_container_set_border_width (GTK_CONTAINER (rx_scrolledwindow), 4); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (rx_scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (rx_scrolledwindow), GTK_SHADOW_IN); rx_textview = gtk_text_view_new (); gtk_widget_show (rx_textview); gtk_container_add (GTK_CONTAINER (rx_scrolledwindow), rx_textview); gtk_widget_set_size_request (rx_textview, 600, 256); gtk_text_view_set_editable (GTK_TEXT_VIEW (rx_textview), FALSE); gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (rx_textview), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (rx_textview), GTK_WRAP_WORD); hbox4 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox4); gtk_frame_set_label_widget (GTK_FRAME (frame2), hbox4); rx_togglebutton = gtk_toggle_button_new (); gtk_widget_show (rx_togglebutton); gtk_box_pack_start (GTK_BOX (hbox4), rx_togglebutton, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (rx_togglebutton), 2); alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); gtk_widget_show (alignment3); gtk_container_add (GTK_CONTAINER (rx_togglebutton), alignment3); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3), 2, 2, 2, 2); hbox5 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox5); gtk_container_add (GTK_CONTAINER (alignment3), hbox5); image2 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image2); gtk_box_pack_start (GTK_BOX (hbox5), image2, FALSE, FALSE, 0); label9 = gtk_label_new_with_mnemonic (_("Receive")); gtk_widget_show (label9); gtk_box_pack_start (GTK_BOX (hbox5), label9, FALSE, FALSE, 0); clear = gtk_button_new (); gtk_widget_show (clear); gtk_box_pack_start (GTK_BOX (hbox4), clear, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (clear), 2); alignment4 = gtk_alignment_new (0.5, 0.5, 0, 0); gtk_widget_show (alignment4); gtk_container_add (GTK_CONTAINER (clear), alignment4); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment4), 2, 2, 2, 2); hbox6 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox6); gtk_container_add (GTK_CONTAINER (alignment4), hbox6); image3 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image3); gtk_box_pack_start (GTK_BOX (hbox6), image3, FALSE, FALSE, 0); label10 = gtk_label_new_with_mnemonic (_("Clear window")); gtk_widget_show (label10); gtk_box_pack_start (GTK_BOX (hbox6), label10, FALSE, FALSE, 0); hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0); frame1 = gtk_frame_new (NULL); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (hbox1), frame1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame1), 4); alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_widget_show (alignment2); gtk_container_add (GTK_CONTAINER (frame1), alignment2); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment2), 2, 2, 2, 2); scope = gtk_drawing_area_new (); gtk_widget_show (scope); gtk_container_add (GTK_CONTAINER (alignment2), scope); gtk_widget_set_size_request (scope, 264, 89); gtk_widget_set_events (scope, GDK_BUTTON_PRESS_MASK); label1 = gtk_label_new (_("Scope")); gtk_widget_show (label1); gtk_frame_set_label_widget (GTK_FRAME (frame1), label1); hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_box_pack_start (GTK_BOX (hbox1), hbox2, TRUE, TRUE, 0); vbox2 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (hbox2), vbox2, FALSE, FALSE, 0); frame4 = gtk_frame_new (NULL); gtk_widget_show (frame4); gtk_box_pack_start (GTK_BOX (vbox2), frame4, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame4), 4); speed_adj = gtk_adjustment_new (20, 10, 60, 1, 10, 0); speed = gtk_spin_button_new (GTK_ADJUSTMENT (speed_adj), 1, 0); gtk_widget_show (speed); gtk_container_add (GTK_CONTAINER (frame4), speed); wpm = gtk_check_button_new_with_mnemonic (_("Auto wpm")); gtk_widget_show (wpm); gtk_frame_set_label_widget (GTK_FRAME (frame4), wpm); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wpm), TRUE); frame5 = gtk_frame_new (NULL); gtk_widget_show (frame5); gtk_box_pack_start (GTK_BOX (vbox2), frame5, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame5), 4); squelch_adj = gtk_adjustment_new (50, 0, 100, 1, 10, 0); squelch = gtk_spin_button_new (GTK_ADJUSTMENT (squelch_adj), 1, 0); gtk_widget_show (squelch); gtk_container_add (GTK_CONTAINER (frame5), squelch); label8 = gtk_label_new (_("Threshold")); gtk_widget_show (label8); gtk_frame_set_label_widget (GTK_FRAME (frame5), label8); frame7 = gtk_frame_new (NULL); gtk_widget_show (frame7); gtk_box_pack_start (GTK_BOX (hbox2), frame7, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame7), 4); alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_widget_show (alignment1); gtk_container_add (GTK_CONTAINER (frame7), alignment1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1), 2, 2, 2, 2); waterfall = gtk_drawing_area_new (); gtk_widget_show (waterfall); gtk_container_add (GTK_CONTAINER (alignment1), waterfall); gtk_widget_set_size_request (waterfall, 258, 89); gtk_widget_set_events (waterfall, GDK_BUTTON_PRESS_MASK); label7 = gtk_label_new (_("Waterfall")); gtk_widget_show (label7); gtk_frame_set_label_widget (GTK_FRAME (frame7), label7); g_signal_connect ((gpointer) main_window, "destroy", G_CALLBACK (on_main_window_destroy), NULL); g_signal_connect ((gpointer) main_window, "delete_event", G_CALLBACK (on_main_window_delete_event), NULL); g_signal_connect ((gpointer) rx_togglebutton, "toggled", G_CALLBACK (on_rx_togglebutton_toggled), NULL); g_signal_connect ((gpointer) clear, "clicked", G_CALLBACK (on_clear_clicked), NULL); g_signal_connect ((gpointer) scope, "expose_event", G_CALLBACK (on_scope_expose_event), NULL); g_signal_connect ((gpointer) scope, "button_press_event", G_CALLBACK (on_scope_button_press_event), NULL); g_signal_connect ((gpointer) speed, "changed", G_CALLBACK (on_speed_changed), NULL); g_signal_connect ((gpointer) wpm, "toggled", G_CALLBACK (on_wpm_toggled), NULL); g_signal_connect ((gpointer) squelch, "changed", G_CALLBACK (on_squelch_changed), NULL); g_signal_connect ((gpointer) waterfall, "expose_event", G_CALLBACK (on_waterfall_expose_event), NULL); g_signal_connect ((gpointer) waterfall, "button_press_event", G_CALLBACK (on_waterfall_button_press_event), NULL); g_signal_connect ((gpointer) waterfall, "size_allocate", G_CALLBACK (on_waterfall_size_allocate), NULL); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (main_window, main_window, "main_window"); GLADE_HOOKUP_OBJECT (main_window, vbox1, "vbox1"); GLADE_HOOKUP_OBJECT (main_window, frame2, "frame2"); GLADE_HOOKUP_OBJECT (main_window, rx_scrolledwindow, "rx_scrolledwindow"); GLADE_HOOKUP_OBJECT (main_window, rx_textview, "rx_textview"); GLADE_HOOKUP_OBJECT (main_window, hbox4, "hbox4"); GLADE_HOOKUP_OBJECT (main_window, rx_togglebutton, "rx_togglebutton"); GLADE_HOOKUP_OBJECT (main_window, alignment3, "alignment3"); GLADE_HOOKUP_OBJECT (main_window, hbox5, "hbox5"); GLADE_HOOKUP_OBJECT (main_window, image2, "image2"); GLADE_HOOKUP_OBJECT (main_window, label9, "label9"); GLADE_HOOKUP_OBJECT (main_window, clear, "clear"); GLADE_HOOKUP_OBJECT (main_window, alignment4, "alignment4"); GLADE_HOOKUP_OBJECT (main_window, hbox6, "hbox6"); GLADE_HOOKUP_OBJECT (main_window, image3, "image3"); GLADE_HOOKUP_OBJECT (main_window, label10, "label10"); GLADE_HOOKUP_OBJECT (main_window, hbox1, "hbox1"); GLADE_HOOKUP_OBJECT (main_window, frame1, "frame1"); GLADE_HOOKUP_OBJECT (main_window, alignment2, "alignment2"); GLADE_HOOKUP_OBJECT (main_window, scope, "scope"); GLADE_HOOKUP_OBJECT (main_window, label1, "label1"); GLADE_HOOKUP_OBJECT (main_window, hbox2, "hbox2"); GLADE_HOOKUP_OBJECT (main_window, vbox2, "vbox2"); GLADE_HOOKUP_OBJECT (main_window, frame4, "frame4"); GLADE_HOOKUP_OBJECT (main_window, speed, "speed"); GLADE_HOOKUP_OBJECT (main_window, wpm, "wpm"); GLADE_HOOKUP_OBJECT (main_window, frame5, "frame5"); GLADE_HOOKUP_OBJECT (main_window, squelch, "squelch"); GLADE_HOOKUP_OBJECT (main_window, label8, "label8"); GLADE_HOOKUP_OBJECT (main_window, frame7, "frame7"); GLADE_HOOKUP_OBJECT (main_window, alignment1, "alignment1"); GLADE_HOOKUP_OBJECT (main_window, waterfall, "waterfall"); GLADE_HOOKUP_OBJECT (main_window, label7, "label7"); return main_window; } GtkWidget* create_error_dialog (void) { GtkWidget *error_dialog; GtkWidget *dialog_vbox1; GtkWidget *frame6; GtkWidget *hbox3; GtkWidget *image1; GtkWidget *error_message; GtkWidget *label6; GtkWidget *dialog_action_area1; GtkWidget *err_quit_button; GtkWidget *err_ok_button; error_dialog = gtk_dialog_new (); gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 4); gtk_window_set_title (GTK_WINDOW (error_dialog), _("Xdemorse")); gtk_window_set_position (GTK_WINDOW (error_dialog), GTK_WIN_POS_MOUSE); gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE); gtk_window_set_type_hint (GTK_WINDOW (error_dialog), GDK_WINDOW_TYPE_HINT_DIALOG); dialog_vbox1 = GTK_DIALOG (error_dialog)->vbox; gtk_widget_show (dialog_vbox1); frame6 = gtk_frame_new (NULL); gtk_widget_show (frame6); gtk_box_pack_start (GTK_BOX (dialog_vbox1), frame6, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame6), 4); hbox3 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox3); gtk_container_add (GTK_CONTAINER (frame6), hbox3); image1 = gtk_image_new_from_stock ("gtk-dialog-error", GTK_ICON_SIZE_DIALOG); gtk_widget_show (image1); gtk_box_pack_start (GTK_BOX (hbox3), image1, FALSE, FALSE, 0); error_message = gtk_label_new (_("Generic Error Message pop-up")); gtk_widget_show (error_message); gtk_box_pack_start (GTK_BOX (hbox3), error_message, FALSE, FALSE, 0); gtk_misc_set_padding (GTK_MISC (error_message), 4, 0); label6 = gtk_label_new (_("Error!")); gtk_widget_show (label6); gtk_frame_set_label_widget (GTK_FRAME (frame6), label6); dialog_action_area1 = GTK_DIALOG (error_dialog)->action_area; gtk_widget_show (dialog_action_area1); gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); err_quit_button = gtk_button_new_from_stock ("gtk-quit"); gtk_widget_show (err_quit_button); gtk_dialog_add_action_widget (GTK_DIALOG (error_dialog), err_quit_button, 0); gtk_container_set_border_width (GTK_CONTAINER (err_quit_button), 2); GTK_WIDGET_SET_FLAGS (err_quit_button, GTK_CAN_DEFAULT); err_ok_button = gtk_button_new_from_stock ("gtk-ok"); gtk_widget_show (err_ok_button); gtk_dialog_add_action_widget (GTK_DIALOG (error_dialog), err_ok_button, GTK_RESPONSE_OK); gtk_container_set_border_width (GTK_CONTAINER (err_ok_button), 2); GTK_WIDGET_SET_FLAGS (err_ok_button, GTK_CAN_DEFAULT); g_signal_connect ((gpointer) error_dialog, "destroy", G_CALLBACK (on_error_dialog_destroy), NULL); g_signal_connect ((gpointer) error_dialog, "delete_event", G_CALLBACK (on_error_dialog_delete_event), NULL); g_signal_connect ((gpointer) err_quit_button, "clicked", G_CALLBACK (on_err_quit_clicked), NULL); g_signal_connect ((gpointer) err_ok_button, "clicked", G_CALLBACK (on_err_ok_button_clicked), NULL); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (error_dialog, error_dialog, "error_dialog"); GLADE_HOOKUP_OBJECT_NO_REF (error_dialog, dialog_vbox1, "dialog_vbox1"); GLADE_HOOKUP_OBJECT (error_dialog, frame6, "frame6"); GLADE_HOOKUP_OBJECT (error_dialog, hbox3, "hbox3"); GLADE_HOOKUP_OBJECT (error_dialog, image1, "image1"); GLADE_HOOKUP_OBJECT (error_dialog, error_message, "error_message"); GLADE_HOOKUP_OBJECT (error_dialog, label6, "label6"); GLADE_HOOKUP_OBJECT_NO_REF (error_dialog, dialog_action_area1, "dialog_action_area1"); GLADE_HOOKUP_OBJECT (error_dialog, err_quit_button, "err_quit_button"); GLADE_HOOKUP_OBJECT (error_dialog, err_ok_button, "err_ok_button"); return error_dialog; } xdemorse-1.3.orig/src/detect.c0000644000175000017500000001343410772450177014654 0ustar pg4ipg4i/* detect.c * * Signal detection 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" #include "detect.h" /* Runtime config data */ extern rc_data_t rc_data; /*------------------------------------------------------------------------*/ /* Get_Fragment() * * Detects the cw beat frequency signal o/p from the radio * receiver and determines the status, (mark or space) of a * 'fragment' (a small fraction, ~1/8) of a Morse code element. * Signal detection is done by using a Goertzel algorithm. */ int Get_Fragment( void ) { int frag_lev, /* Level of the Morse signal 'fragment' */ frag_timer, /* Counter for timing duration of fragment */ block_size, /* Block size (N) of the Goertzel algorithm */ up_steps, /* Num of consecutive increasing signal levels */ dn_steps, /* Num of consecutive decreasing signal levels */ idx; /* Variables for the Goertzel algorithm */ double q0, q1, q2; /* Goertzel block size depends on Morse speed */ block_size = detector_data.frag_len * rc_data.unit_elem; /* Buffer dsp samples of input signal for a fragment */ for(frag_timer = 0; frag_timer < detector_data.frag_len; frag_timer++ ) { /* Get next signal sample from buffer, abort on error */ detector_data.samples_buff[detector_data.samples_buff_idx] = Signal_Sample(); if( isFlagSet(DSP_IO_ERROR) ) return(-1); /* Advance/Reset circular buffers' index */ if( ++detector_data.samples_buff_idx >= detector_data.samples_buff_len ) detector_data.samples_buff_idx = 0; } /* for( frag_timer = 0; frag_timer < frag_len ... */ /** Calculate signal fragment level over a block **/ /* Backstep buffer index for use of samples */ detector_data.samples_buff_idx -= block_size; if( detector_data.samples_buff_idx < 0 ) detector_data.samples_buff_idx += detector_data.samples_buff_len; /* Calculate fragment level using Goertzel algorithm */ q1 = q2 = 0.0; for( idx = 0; idx < block_size; idx++ ) { q0 = detector_data.coeff * q1 - q2 + detector_data.samples_buff[detector_data.samples_buff_idx]; q2 = q1; q1 = q0; /* Reset circular buffers' index */ if( ++detector_data.samples_buff_idx >= detector_data.samples_buff_len ) detector_data.samples_buff_idx = 0; } /* Scalar magnitude of input signal scaled by block size */ q1 /= (double)block_size; q2 /= (double)block_size; frag_lev = (int)(q1*q1 + q2*q2 - q1*q2*detector_data.coeff); /* Save signal power level to circular buffer */ detector_data.sig_level_buff[detector_data.sig_level_idx] = frag_lev; if( ++detector_data.sig_level_idx >= rc_data.max_unit ) detector_data.sig_level_idx = 0; /* Backstep buffer index for use of fragment levels */ detector_data.sig_level_idx -= rc_data.unit_elem; if( detector_data.sig_level_idx < 0 ) detector_data.sig_level_idx += rc_data.max_unit; /* Count the number of "steps" in the signal's edge that are * in the same direction (increasing or decreasing amplitude) */ up_steps = dn_steps = 0; for( idx = 1; idx < rc_data.unit_elem; idx++ ) { int tmp1, tmp2; /* Compare successive signal levels */ tmp1 = detector_data.sig_level_buff[detector_data.sig_level_idx]; if( ++detector_data.sig_level_idx >= rc_data.max_unit ) detector_data.sig_level_idx = 0; tmp2 = detector_data.sig_level_buff[detector_data.sig_level_idx]; /* Successive levels are compared for more * than STEP_THRESHOLD difference up or down */ if( STEP_THRESHOLD*tmp1 < 100*tmp2 ) up_steps++; else if( 100*tmp1 > STEP_THRESHOLD*tmp2 ) dn_steps++; } if( ++detector_data.sig_level_idx >= rc_data.max_unit ) detector_data.sig_level_idx = 0; /* Set tone status. */ if( 100*up_steps > rc_data.det_thr*(rc_data.unit_elem-1) ) Set_Flag( MARK_TONE ); else if( 100*dn_steps > rc_data.det_thr*(rc_data.unit_elem-1) ) Clear_Flag( MARK_TONE ); /* Display signal graph (scope) */ if( isFlagSet(DISPLAY_DETECTOR) ) Display_Detector( (87*up_steps)/rc_data.unit_elem ); else if( isFlagSet(DISPLAY_SIGNAL) ) Display_Signal( frag_lev ); return( frag_lev ); } /* End of Get_Fragment() */ /*------------------------------------------------------------------------*/ /* Initialize_Detector() * * Initializes variables and allocates buffers * for the Goertzel tone detector */ gboolean Initialize_Detector( void ) { double w = 2.0 * M_PI * (double)rc_data.tone_freq / (double)rc_data.dsp_speed; detector_data.cosw = cos(w); detector_data.sinw = sin(w); detector_data.coeff = 2.0 * detector_data.cosw; detector_data.samples_buff_idx = 0; detector_data.sig_level_idx = 0; detector_data.frag_len = ( rc_data.dsp_speed * CYCLES_PER_FRAG ) / rc_data.tone_freq; detector_data.samples_buff_len = (CYCLES_PER_FRAG *rc_data.max_unit *rc_data.dsp_speed) / rc_data.tone_freq; size_t alloc = (CYCLES_PER_FRAG *rc_data.max_unit *rc_data.dsp_speed) / rc_data.tone_freq; if( !mem_alloc((void *)&detector_data.samples_buff, alloc) ) return( FALSE ); alloc = sizeof(int) * rc_data.max_unit; if( !mem_alloc( (void *)&detector_data.sig_level_buff, alloc) ) return( FALSE ); return( TRUE ); } /* Initialize_Detector() */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/support.c0000644000175000017500000000712711111311621015074 0ustar pg4ipg4i/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "support.h" GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name) { GtkWidget *parent, *found_widget; for (;;) { if (GTK_IS_MENU (widget)) parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); else parent = widget->parent; if (!parent) parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); if (parent == NULL) break; widget = parent; } found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), widget_name); if (!found_widget) g_warning ("Widget not found: %s", widget_name); return found_widget; } static GList *pixmaps_directories = NULL; /* Use this function to set the directory containing installed pixmaps. */ void add_pixmap_directory (const gchar *directory) { pixmaps_directories = g_list_prepend (pixmaps_directories, g_strdup (directory)); } /* This is an internally used function to find pixmap files. */ static gchar* find_pixmap_file (const gchar *filename) { GList *elem; /* We step through each of the pixmaps directory to find it. */ elem = pixmaps_directories; while (elem) { gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, G_DIR_SEPARATOR_S, filename); if (g_file_test (pathname, G_FILE_TEST_EXISTS)) return pathname; g_free (pathname); elem = elem->next; } return NULL; } /* This is an internally used function to create pixmaps. */ GtkWidget* create_pixmap (GtkWidget *widget, const gchar *filename) { gchar *pathname = NULL; GtkWidget *pixmap; if (!filename || !filename[0]) return gtk_image_new (); pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return gtk_image_new (); } pixmap = gtk_image_new_from_file (pathname); g_free (pathname); return pixmap; } /* This is an internally used function to create pixmaps. */ GdkPixbuf* create_pixbuf (const gchar *filename) { gchar *pathname = NULL; GdkPixbuf *pixbuf; GError *error = NULL; if (!filename || !filename[0]) return NULL; pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return NULL; } pixbuf = gdk_pixbuf_new_from_file (pathname, &error); if (!pixbuf) { fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", pathname, error->message); g_error_free (error); } g_free (pathname); return pixbuf; } /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description) { gint n_actions, i; n_actions = atk_action_get_n_actions (action); for (i = 0; i < n_actions; i++) { if (!strcmp (atk_action_get_name (action, i), action_name)) atk_action_set_description (action, i, description); } } xdemorse-1.3.orig/src/fft.c0000644000175000017500000000531310772444377014165 0ustar pg4ipg4i/* fft.c * * FFT functions of xdemorse-fft 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" /* fft in/out buffers */ int *fft_in_r, *fft_out_r, *fft_out_i; /* Scaled-up, integer, sin/cos tables */ static int *isin, *icos; /*------------------------------------------------------------------------*/ /* Ifft_init() * * Initializes Ifft() */ void Ifft_init( int fft_size ) { int i; double w, tpi; /* Allocate fft buffers */ i = sizeof(int) * fft_size; mem_alloc( (void *)&fft_in_r, i ); mem_alloc( (void *)&isin, i ); mem_alloc( (void *)&icos, i ); i = sizeof(int) * fft_size / 2; mem_alloc( (void *)&fft_out_r, i ); mem_alloc( (void *)&fft_out_i, i ); /* Make sin/cos tables */ tpi = 2.0 * M_PI; for( i = 0; i < fft_size; i++ ) { w = tpi * (double)i / (double)fft_size; isin[i] = (int)(32.0 * sin(w) + 0.5); icos[i] = (int)(32.0 * cos(w) + 0.5); } } /* Ifft_init() */ /*------------------------------------------------------------------------*/ /* Ifft() * * Simple, integer-only, FFT function */ void Ifft( int fft_size ) { int i, j, w; /* In-phase and quadrature summation */ int sum_i, sum_q; int k = fft_size/2; /* Calculate output bins */ for( i = 0; i < k; i++ ) { sum_i = sum_q = w = 0; /* Summate input values */ for( j = 0; j < fft_size; j++ ) { w += i; if( w >= fft_size ) w -= fft_size; sum_i += fft_in_r[j] * isin[w]; sum_q += fft_in_r[j] * icos[w]; } /* Normalized summations to bins */ fft_out_r[i] = sum_i/fft_size; fft_out_i[i] = sum_q/fft_size; } /* for( i = 0; i < k; i++ ) */ } /* Ifft() */ /*------------------------------------------------------------------------*/ gboolean mem_alloc( void **ptr, int req ) { *ptr = malloc( req ); if( *ptr == NULL ) { perror( "xdemorse: Memory allocation request:" ); Error_Dialog( "Memory allocation request failed" "Quit xdemorse and correct" ); return( FALSE ); } bzero( *ptr, req ); return( TRUE ); } /* End of void mem_alloc() */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/callbacks.c0000644000175000017500000001347710772754057015336 0ustar pg4ipg4i#ifdef HAVE_CONFIG_H # include #endif #include #include "callbacks.h" #include "interface.h" #include "support.h" #include "xdemorse.h" /* Speed and squelch spin buttond */ extern GtkSpinButton *gbl_speed, *gbl_squelch; /* Global widgets */ extern GtkWidget *gbl_rx_scrolledwindow, *gbl_scope, *gbl_scope_label; GtkWidget *error_dialog = NULL; /* Text buffer for text viewer */ GtkTextBuffer *gbl_rx_text_buffer; /* Runtime config data */ extern rc_data_t rc_data; /* Waterfall window pixbuf */ extern GdkPixbuf *gbl_wfall_pixbuf; extern guchar *gbl_wfall_pixels; extern gint gbl_wfall_rowstride, gbl_wfall_n_channels, gbl_wfall_width, gbl_wfall_height; /* Error_Dialog() * * Opens an error dialog box */ void Error_Dialog( char *message ) { GtkWidget *label; if( error_dialog != NULL ) return; error_dialog = create_error_dialog(); label = lookup_widget( error_dialog, "error_message" ); gtk_label_set_text( GTK_LABEL(label), message ); gtk_widget_show( error_dialog ); } void on_main_window_destroy( GtkObject *object, gpointer user_data) { Cleanup(); gtk_main_quit(); } gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data) { return FALSE; } gboolean on_scope_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { /* Draw scope background */ gdk_draw_rectangle( widget->window, widget->style->white_gc, TRUE, 4, 4, 255, 80 ); /* Draw scope frame */ gdk_draw_rectangle( widget->window, widget->style->black_gc, FALSE, 3, 3, 256, 81 ); gtk_label_set_text( GTK_LABEL(gbl_scope_label), "Signal Input" ); return TRUE; } gboolean on_scope_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data) { switch( event->button ) { case 1: /* Button 1 pressed */ Toggle_Flag( DISPLAY_SIGNAL ); Clear_Flag( DISPLAY_DETECTOR ); break; case 2: /* Button 3 pressed */ Clear_Flag( DISPLAY_SIGNAL ); Clear_Flag( DISPLAY_DETECTOR ); break; case 3: /* Button 2 pressed */ Toggle_Flag( DISPLAY_DETECTOR ); Clear_Flag( DISPLAY_SIGNAL ); } /* switch( event->button ) */ /* Set scope label */ if( isFlagSet(DISPLAY_SIGNAL) ) gtk_label_set_text( GTK_LABEL(gbl_scope_label), "Signal Input" ); else if( isFlagSet(DISPLAY_DETECTOR) ) gtk_label_set_text( GTK_LABEL(gbl_scope_label), "Detector Output" ); else gtk_label_set_text( GTK_LABEL(gbl_scope_label), "Stopped" ); return TRUE; } void on_speed_changed( GtkEditable *editable, gpointer user_data) { rc_data.unit_elem = gtk_spin_button_get_value_as_int( gbl_speed ); rc_data.unit_elem = (60 * rc_data.tone_freq) / (50 * CYCLES_PER_FRAG * rc_data.unit_elem); } void on_squelch_changed( GtkEditable *editable, gpointer user_data) { rc_data.det_thr = (int)gtk_spin_button_get_value( gbl_squelch ); } void on_err_quit_clicked( GtkButton *button, gpointer user_data) { Cleanup(); gtk_main_quit(); } void on_clear_clicked( GtkButton *button, gpointer user_data) { gtk_text_buffer_set_text( gbl_rx_text_buffer, "", -1 ); } gboolean on_waterfall_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { if( gbl_wfall_pixbuf == NULL ) return( TRUE ); gdk_draw_pixbuf( widget->window, NULL, gbl_wfall_pixbuf, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height, GDK_RGB_DITHER_NONE, 0, 0 ); return TRUE; } gboolean on_waterfall_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data) { if( event->button == 1 ) { if( isFlagSet(CAT_SETUP) ) Tune_Tcvr( event->x ); } else Toggle_Flag( REVERSE_VIDEO ); return TRUE; } void on_err_ok_button_clicked( GtkButton *button, gpointer user_data) { gtk_widget_destroy( error_dialog ); } void on_wpm_toggled (GtkToggleButton *togglebutton, gpointer user_data) { if( gtk_toggle_button_get_active(togglebutton) ) Set_Flag( ADAPT_SPEED ); else Clear_Flag( ADAPT_SPEED ); } void on_error_dialog_destroy (GtkObject *object, gpointer user_data) { error_dialog = NULL; } gboolean on_error_dialog_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { return TRUE; } void on_waterfall_size_allocate (GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) { /* Destroy existing pixbuff */ if( gbl_wfall_pixbuf != NULL ) { g_object_unref( G_OBJECT(gbl_wfall_pixbuf) ); gbl_wfall_pixbuf = NULL; } /* Create waterfall pixbuf */ gbl_wfall_pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, allocation->width, allocation->height ); if( gbl_wfall_pixbuf == NULL ) { Error_Dialog( "Failed to create pixbuf for waterfall" ); return; } gbl_wfall_pixels = gdk_pixbuf_get_pixels( gbl_wfall_pixbuf ); gbl_wfall_width = gdk_pixbuf_get_width ( gbl_wfall_pixbuf ); gbl_wfall_height = gdk_pixbuf_get_height( gbl_wfall_pixbuf ); gbl_wfall_rowstride = gdk_pixbuf_get_rowstride( gbl_wfall_pixbuf ); gbl_wfall_n_channels = gdk_pixbuf_get_n_channels( gbl_wfall_pixbuf ); Clear_Pixbuf(); } void on_rx_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) { if( gtk_toggle_button_get_active(togglebutton) && isFlagSet(ENABLE_RECEIVE) ) gtk_idle_add( Print_Character, "RX" ); else g_idle_remove_by_data( "RX" ); } xdemorse-1.3.orig/src/interface.h0000644000175000017500000000021211111311621015311 0ustar pg4ipg4i/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ GtkWidget* create_main_window (void); GtkWidget* create_error_dialog (void); xdemorse-1.3.orig/src/main.c0000644000175000017500000004014210773350052014314 0ustar pg4ipg4i/* * Initial main.c file generated by Glade. Edit as required. * Glade will not overwrite this file. */ #ifdef HAVE_CONFIG_H # include #endif #include #include "interface.h" #include "support.h" #include "xdemorse.h" /* xdemorse main window */ GtkWidget *main_window; /* Global widgets */ GtkWidget *gbl_rx_scrolledwindow, *gbl_scope, *gbl_waterfall, *gbl_scope_label; /* Speed and squelch spin button */ GtkSpinButton *gbl_speed, *gbl_squelch; /* Text buffer for text viewer */ GtkTextBuffer *gbl_rx_text_buffer; int dsp_fd, /* File descriptor of dsp device */ mix_fd; /* File descriptor of mixer device */ /* Signal handler */ static void sig_handler( int signal ); /* Runtime config data */ rc_data_t rc_data; /* Waterfall window pixbuf */ GdkPixbuf *gbl_wfall_pixbuf = NULL; guchar *gbl_wfall_pixels; gint gbl_wfall_rowstride, gbl_wfall_n_channels, gbl_wfall_width, gbl_wfall_height; /*------------------------------------------------------------------------*/ int main (int argc, char *argv[]) { /* Main window */ GtkWidget *main_window; /* Command line option returned by getopt() */ int option; /* getopt() variables */ extern char *optarg; extern int optind, opterr, optopt; /* New and old actions for sigaction() */ struct sigaction sa_new, sa_old; /* Initialize new actions */ sa_new.sa_handler = sig_handler; sigemptyset( &sa_new.sa_mask ); sa_new.sa_flags = 0; /* Register function to handle signals */ sigaction( SIGINT, &sa_new, &sa_old ); sigaction( SIGSEGV, &sa_new, 0 ); sigaction( SIGFPE, &sa_new, 0 ); sigaction( SIGTERM, &sa_new, 0 ); sigaction( SIGABRT, &sa_new, 0 ); gtk_set_locale (); gtk_init (&argc, &argv); Set_Flag( ADAPT_SPEED | DISPLAY_SIGNAL); rc_data.unit_elem = 15; /* Process command line options */ while( (option = getopt(argc, argv, "hlv") ) != -1 ) switch( option ) { case 'h': /* Print usage and exit */ Usage(); exit( 0 ); case 'l': /* Print available mixer devices */ { /* Sound device names from souncard.h */ char *dev_name[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; int device; puts("Printing out mixer device names" ); for( device = 0; device < SOUND_MIXER_NRDEVICES; device++ ) puts( dev_name[device] ); exit( 0 ); } case 'v': /* Print version */ printf( "%s %s\n", PACKAGE, VERSION ); exit( 0 ); default: /* Print usage and exit */ Usage(); exit( -1 ); } /* End of switch( option ) */ /* * The following code was added by Glade to create one of each component * (except popup menus), just so that you see something after building * the project. Delete any components that you don't want shown initially. */ main_window = create_main_window (); gtk_window_set_title( GTK_WINDOW(main_window), PACKAGE"-"VERSION ); /* Get Rx text buffer and scroller */ gbl_rx_text_buffer = gtk_text_view_get_buffer ( GTK_TEXT_VIEW(lookup_widget(main_window, "rx_textview")) ); gbl_rx_scrolledwindow = lookup_widget( main_window, "rx_scrolledwindow" ); /* Get widgets and spin buttons */ gbl_scope = lookup_widget( main_window, "scope" ); gbl_waterfall = lookup_widget( main_window, "waterfall" ); gbl_scope_label = lookup_widget( main_window, "label1" ); gbl_speed = GTK_SPIN_BUTTON( lookup_widget(main_window, "speed") ); gbl_squelch = GTK_SPIN_BUTTON( lookup_widget(main_window, "squelch") ); rc_data.det_thr = (int)gtk_spin_button_get_value( gbl_squelch ); rc_data.spd_wpm = (int)gtk_spin_button_get_value( gbl_speed ); gtk_widget_show (main_window); /* Initialize FFT */ Ifft_init( FFT_SIZE ); /* Load runtime config file, abort on error */ gtk_idle_add( Load_Config, NULL ); gtk_main (); return 0; } /*------------------------------------------------------------------------*/ /* Load_Config() * * Loads the xdemorserc configuration file */ gboolean Load_Config( gpointer data ) { char rc_fpath[64], /* File path to xdemorserc */ line[81]; /* Buffer for Load_Line */ /* Config file pointer */ FILE *xdemorserc; /* Setup file path to xdemorserc */ snprintf( rc_fpath, 64, "%s/.xdemorserc", getenv("HOME") ); /* Open xdemorserc file */ xdemorserc = fopen( rc_fpath, "r" ); if( xdemorserc == NULL ) { perror( rc_fpath ); Error_Dialog( "Failed to open xdemorserc file\n" "Quit xdemorse and correct" ); return( FALSE ); } /*** Read runtime configuration data ***/ /* Read mixer dev, abort if EOF */ if( Load_Line(line, xdemorserc, "Mixer Device" ) != SUCCESS ) return( FALSE ); strncpy( rc_data.mix_dev, line, 20 ); rc_data.mix_dev[20] = '\0'; /* Read input DSP dev, abort if EOF */ if( Load_Line(line, xdemorserc, "Input DSP Device") != SUCCESS ) return( FALSE ); strncpy( rc_data.dsp_dev, line, 20 ); rc_data.dsp_dev[20] = '\0'; /* Read DSP speed Samples/sec, abort if EOF */ if( Load_Line(line, xdemorserc, "DSP Speed" ) != SUCCESS ) return( FALSE ); rc_data.dsp_speed = atoi( line ); /* Read recording source, abort if EOF */ if( Load_Line(line, xdemorserc, "Recording Source") != SUCCESS ) return( FALSE ); strncpy( rc_data.rec_src, line, 20 ); rc_data.rec_src[20] = '\0'; /* Read Recording level device, abort if EOF */ if( Load_Line(line, xdemorserc, "Recording Level Device") != SUCCESS ) return( FALSE ); strncpy( rc_data.inp_lev, line, 20 ); rc_data.inp_lev[20] = '\0'; /* Read Recording level, abort if EOF */ if( Load_Line(line, xdemorserc, "Recording Level") != 0 ) return( FALSE ); rc_data.rec_lev = atoi( line ); /* Read stero/mono mode, abort if EOF */ if( Load_Line(line, xdemorserc, "Stero|Mono Mode") != SUCCESS ) return( FALSE ); line[6] = '\0'; if( strcmp(line, "STEREO") == 0 ) rc_data.num_chn = 2; else if( strcmp(line, "MONO") == 0 ) rc_data.num_chn = 1; else { Error_Dialog( "Error reading Stereo or Mono mode\n" "Quit and correct xdemorserc" ); return( FALSE ); } /* Read channel used, abort if EOF */ if( Load_Line(line, xdemorserc, "Left|Right Channel") != SUCCESS ) return( FALSE ); line[5] = '\0'; if( strcmp(line, "LEFT") == 0 ) rc_data.use_chn = 0; else if( strcmp(line, "RIGHT") == SUCCESS ) rc_data.use_chn = 1; else { Error_Dialog( "Error reading Stereo channel to use\n" "Quit and correct xdemorserc" ); return( FALSE ); } /* Read max WPM, abort if EOF */ if( Load_Line(line, xdemorserc, "Maximum WPM") != SUCCESS ) return( FALSE ); rc_data.min_unit = atoi( line ); /* Read min WPM, abort if EOF */ if( Load_Line(line, xdemorserc, "Minimum WPM") != SUCCESS ) return( FALSE ); rc_data.max_unit = atoi( line ); /* Check range of Morse speeds. At this point max_unit * holds minimum wpm and min_unit holds maximum wpm */ if( (rc_data.max_unit < MIN_SPEED) || (rc_data.min_unit > MAX_SPEED) ) { Error_Dialog( "Morse code speed (WPM)\n" "range is out of limits\n" "Quit and correct xdemorserc" ); return( FALSE ); } /* Set spinbutton range */ gtk_spin_button_set_range( gbl_speed, (gdouble)rc_data.max_unit, (gdouble)rc_data.min_unit ); /* Read and check initial WPM, abort if EOF */ if( Load_Line(line, xdemorserc, "Initial WPM") != SUCCESS ) return( FALSE ); int wpm = atoi( line ); /* Check initial Morse speed. At this point max_unit * holds minimum wpm and min_unit holds maximum wpm */ if( (wpm > rc_data.min_unit) || (wpm < rc_data.max_unit) ) { Error_Dialog( "Initial Morse code speed (WPM)\n" "is out of specified range\n" "Quit and correct xdemorserc" ); return( FALSE ); } /* Read word wrap column, abort if EOF */ if( Load_Line(line, xdemorserc, "Word Wrap Column") != SUCCESS ) return( FALSE ); rc_data.wrd_wrp = atoi( line ); /* Read FT-847 serial port device, abort if EOF */ if( Load_Line(line, xdemorserc, "FT-847 Serial Port") != SUCCESS ) return( FALSE ); strncpy( rc_data.ft847_serial, line, 31 ); rc_data.ft847_serial[31] = '\0'; /* Read FT-857 serial port device, abort if EOF */ if( Load_Line(line, xdemorserc, "FT-857 Serial Port") != SUCCESS ) return( FALSE ); strncpy( rc_data.ft857_serial, line, 31 ); rc_data.ft857_serial[31] = '\0'; /* Read CAT enable flag, abort if EOF */ if( Load_Line(line, xdemorserc, "CAT Enable") != SUCCESS ) return( FALSE ); if( strcmp(line, "FT847") == 0 ) rc_data.tcvr_type = FT847; else if( strcmp(line, "FT857") == 0 ) rc_data.tcvr_type = FT857; else if( strcmp(line, "NONE") == 0 ) rc_data.tcvr_type = NONE; else { rc_data.tcvr_type = NONE; Error_Dialog( "Error reading Transceiver type\n" "Quit and correct xdemorserc" ); } /* Read input tone (Rx BFO) frequency */ if( Load_Line(line, xdemorserc, "Input Tone") != SUCCESS ) return( FALSE ); rc_data.tone_freq = atoi( line ); /* The tone freq must be rounded so that the fft_stride * is an integer otherwise the waterfall is not accurate */ rc_data.fft_stride = rc_data.dsp_speed/rc_data.tone_freq/4; rc_data.tone_freq = rc_data.dsp_speed/rc_data.fft_stride/4; /* Calculate parameters that depend on above */ rc_data.max_unit = (60*rc_data.tone_freq) / (50*CYCLES_PER_FRAG*rc_data.max_unit); rc_data.min_unit = (60*rc_data.tone_freq) / (50*CYCLES_PER_FRAG*rc_data.min_unit); gtk_spin_button_set_value( gbl_speed, (gdouble)wpm ); rc_data.unit_elem = (60 * rc_data.tone_freq) / (50 * CYCLES_PER_FRAG * wpm); rc_data.red_line = FFT_SIZE / 4; /* Select Transceiver type */ switch( rc_data.tcvr_type ) { case FT847: Set_Flag( ENABLE_CAT | ENABLE_CAT_847 ); Open_Tcvr_Serial(); break; case FT857: Set_Flag( ENABLE_CAT | ENABLE_CAT_857 ); Open_Tcvr_Serial(); break; case NONE: Clear_Flag( ENABLE_CAT ); } /* Allocate memory to recv samples buffer */ rc_data.buffer_idx = rc_data.buffer_size = BUFFER_SIZE * rc_data.num_chn; rc_data.buffer = malloc( (size_t)rc_data.buffer_size ); if( rc_data.buffer == NULL ) { Error_Dialog( "Memory allocation for buffer failed\n" "Quit xdemorse and correct" ); return( FALSE ); } fclose( xdemorserc ); /* Enable receiving Morse code */ if( Setup_Sound_Card() && Initialize_Detector() ) Set_Flag( ENABLE_RECEIVE ); return( FALSE ); } /* End of Load_Config() */ /*------------------------------------------------------------------*/ /* Load_Line() * * Loads a line from a file, aborts on failure. Lines beginning * with a '#' are ignored as comments. At the end of file EOF is * returned. Lines assumed maximum 80 characters long. */ int Load_Line( char *buff, FILE *pfile, char *messg ) { int num_chr, /* Number of characters read, excluding lf/cr */ chr; /* Character read by getc() */ char err_msg[128]; /* Prepare error message */ snprintf( err_msg, 128, "Error reading %s\n" "Premature EOF (End Of File)", messg ); /* Clear buffer at start */ buff[0] = '\0'; num_chr = 0; /* Get next character, return error if chr = EOF */ if( (chr = fgetc(pfile)) == EOF ) { fprintf( stderr, "xdemorse: %s\n", err_msg ); Error_Dialog( err_msg ); return( EOF ); } /* Ignore commented lines, white spaces and eol/cr */ while( (chr == '#') || (chr == ' ') || (chr == HT ) || (chr == CR ) || (chr == LF ) ) { /* Go to the end of line (look for LF or CR) */ while( (chr != CR) && (chr != LF) ) /* Get next character, return error if chr = EOF */ if( (chr = fgetc(pfile)) == EOF ) { fprintf( stderr, "xdemorse: %s\n", err_msg ); Error_Dialog( err_msg ); return( EOF ); } /* Dump any CR/LF remaining */ while( (chr == CR) || (chr == LF) ) /* Get next character, return error if chr = EOF */ if( (chr = fgetc(pfile)) == EOF ) { fprintf( stderr, "xdemorse: %s\n", err_msg ); Error_Dialog( err_msg ); return( EOF ); } } /* End of while( (chr == '#') || ... */ /* Continue reading characters from file till * number of characters = 80 or EOF or CR/LF */ while( num_chr < 80 ) { /* If LF/CR reached before filling buffer, return line */ if( (chr == LF) || (chr == CR) ) break; /* Enter new character to line buffer */ buff[num_chr++] = chr; /* Get next character */ if( (chr = fgetc(pfile)) == EOF ) { /* Terminate buffer as a string if chr = EOF */ buff[num_chr] = '\0'; return( SUCCESS ); } /* Abort if end of line not reached at 80 char. */ if( (num_chr == 80) && (chr != LF) && (chr != CR) ) { /* Terminate buffer as a string */ buff[num_chr] = '\0'; snprintf( err_msg, 128, "Error reading %s\n" "Line longer than 80 characters", messg ); fprintf( stderr, "xdemorse: %s\n%s\n", err_msg, buff ); Error_Dialog( err_msg ); return( ERROR ); } } /* End of while( num_chr < max_chr ) */ /* Terminate buffer as a string */ buff[num_chr] = '\0'; return( SUCCESS ); } /* End of Load_Line() */ /*------------------------------------------------------------------*/ /* Print_Character() * * Prints a character to a text view port */ gboolean Print_Character( gpointer data ) { /* Text buffer marker */ static GtkTextIter iter; GtkAdjustment *adjustment; char dec_char, /* Decoded Morse character */ char2text[2]; /* Convert char to string */ /* Number of chars printed on a line */ static int line_idx = 0; /* Print decoded characters with word wrap */ if( (dec_char = Get_Character()) ) { /* Do word wrapping */ if( (line_idx++ > rc_data.wrd_wrp) && (dec_char == ' ') ) { dec_char = '\n'; line_idx = 0; } /* Convert char to 'text' */ char2text[0] = dec_char; char2text[1] = '\0'; /* Print character */ gtk_text_buffer_get_iter_at_offset( gbl_rx_text_buffer, &iter, gtk_text_buffer_get_char_count (gbl_rx_text_buffer) ); gtk_text_buffer_insert( gbl_rx_text_buffer, &iter, char2text, -1 ); /* Scroll Text View to bottom on LF */ if( (dec_char == '\n') ) { adjustment = gtk_scrolled_window_get_vadjustment ( GTK_SCROLLED_WINDOW(gbl_rx_scrolledwindow) ); gtk_adjustment_set_value( adjustment, adjustment->upper ); } } /* if( dec_char = Get_Character() ) */ if( isFlagClear(DSP_IO_ERROR) ) return( TRUE ); else return( FALSE ); } /* Print_Character() */ /*------------------------------------------------------------------------*/ /* Usage() * * Prints usage information */ void Usage( void ) { fprintf( stderr, "%s\n", "Usage: demorse [-hv]" ); fprintf( stderr, "%s\n", " -h: Print this usage information and exit"); fprintf( stderr, "%s\n", " -v: Print version number and exit"); } /* End of Usage() */ /*------------------------------------------------------------------------*/ /* sig_handler() * * Signal Action Handler function */ static void sig_handler( int signal ) { /* Wrap up and quit */ Cleanup(); fprintf( stderr, "\n" ); switch( signal ) { case SIGINT : fprintf( stderr, "%s\n", "xdemorse: Exiting via User Interrupt" ); exit( signal ); case SIGSEGV : fprintf( stderr, "%s\n", "xdemorse: Segmentation Fault" ); exit( signal ); case SIGFPE : fprintf( stderr, "%s\n", "xdemorse: Floating Point Exception" ); exit( signal ); case SIGABRT : fprintf( stderr, "%s\n", "xdemorse: Abort Signal received" ); exit( signal ); case SIGTERM : fprintf( stderr, "%s\n", "xdemorse: Termination Request received" ); exit( signal ); } } /* End of sig_handler() */ /*------------------------------------------------------------------------*/ /* Functions for testing and setting/clearing flow control flags * * See xdemorse.h for definition of flow control flags */ /* An int variable holding the single-bit flags */ static int Flags = 0; int isFlagSet( int flag ) { return( (Flags & flag) == flag ); } int isFlagClear( int flag ) { return( (~Flags & flag) == flag ); } void Set_Flag( int flag ) { Flags |= flag; } void Clear_Flag( int flag ) { Flags &= ~flag; } void Toggle_Flag( int flag ) { Flags ^= flag; } /*------------------------------------------------------------------------*/ /* Cleanup() * * Cleans up before quitting */ void Cleanup( void ) { /* Release sound card */ if( dsp_fd > 0 ) { close( dsp_fd ); dsp_fd = 0; } if( mix_fd > 0 ) { close( mix_fd ); mix_fd = 0; } Close_Tcvr_Serial(); } /* Cleanup( void ) */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/cat.c0000644000175000017500000002273710772442133014152 0ustar pg4ipg4i/* cat.c * * Yaesu FT847 CAT control functions for the xdemorse application */ /* * xdemorse: An application to decode and display * Morse code signals using the computer's sound card. * * Copyright (C) 2003 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" #include /* Average bin values */ extern int gbl_bin_ave[]; /* Command codes for FT847 CAT */ unsigned char CAT_ON[] = { 0x00, 0, 0, 0, 0x00 }, CAT_OFF[] = { 0x00, 0, 0, 0, 0x80 }, PTT_ON[] = { 0x00, 0, 0, 0, 0x08 }, PTT_OFF[] = { 0x00, 0, 0, 0, 0x88 }, MODE_LSB[] = { 0x00, 0, 0, 0, 0x07 }, MODE_USB[] = { 0x01, 0, 0, 0, 0x07 }, MODE_CW[] = { 0x02, 0, 0, 0, 0x07 }, MODE_CWR[] = { 0x03, 0, 0, 0, 0x07 }, MODE_CWN[] = { 0x82, 0, 0, 0, 0x07 }, MODE_CWNR[] = { 0x83, 0, 0, 0, 0x07 }, MODE_DIG[] = { 0x0a, 0, 0, 0, 0x07 }, MODE_PKT[] = { 0x0c, 0, 0, 0, 0x07 }, RX_STATUS[] = { 0x00, 0, 0, 0, 0xE7 }, MAIN_VFO[] = { 0x00, 0, 0, 0, 0x03 }; #define WRITE_RX_VFO 0x01 /* Runtime config data */ extern rc_data_t rc_data; /*------------------------------------------------------------------------*/ /* Serial port File descriptor */ static int tcvr_serial_fd = 0; /* Original serial port options */ static struct termios tcvr_serial_old_options; /* Open_Tcvr_Serial() * * Opens Tcvr's Serial Port device, returns the file * descriptor tcvr_serial_fd on success or exits on error */ void Open_Tcvr_Serial( void ) { struct termios new_options; /* New serial port options */ struct flock lockinfo; /* File lock information */ /* For testing serial port */ unsigned char test; /* Serial port name */ char serial_port[15]; /* Abort if serial already open */ if( isFlagSet(CAT_SETUP) ) return; /* Open Serial device, exit on error */ if( isFlagSet(ENABLE_CAT_847) ) strcpy( serial_port, rc_data.ft847_serial ); else if( isFlagSet(ENABLE_CAT_857) ) strcpy( serial_port, rc_data.ft857_serial ); tcvr_serial_fd = open( serial_port, O_RDWR | O_NOCTTY ); if( tcvr_serial_fd < 0 ) { char message[32]; perror( serial_port ); snprintf( message, 32, "Failed to open %s", serial_port ); Error_Dialog( message ); Set_Flag( SERIAL_IO_ERROR ); return; } /* Attempt to lock entire Serial port device file */ lockinfo.l_type = F_WRLCK; lockinfo.l_whence = SEEK_SET; lockinfo.l_start = 0; lockinfo.l_len = 0; /* If Serial device is already locked, abort */ if( fcntl( tcvr_serial_fd, F_SETLK, &lockinfo ) < 0 ) { char message[60]; fcntl( tcvr_serial_fd, F_GETLK, &lockinfo ); snprintf( message, 60, "Failed to lock %s\n" "Device locked by pid %d", serial_port, lockinfo.l_pid ); Error_Dialog( message ); Set_Flag( SERIAL_IO_ERROR ); return; } /* Save the current serial port options */ tcgetattr( tcvr_serial_fd, &tcvr_serial_old_options ); /* Read the current serial port options */ tcgetattr( tcvr_serial_fd, &new_options ); /* Set the i/o baud rates */ if( isFlagSet(ENABLE_CAT_847) ) { cfsetispeed( &new_options, B57600 ); cfsetospeed( &new_options, B57600 ); } else if( isFlagSet(ENABLE_CAT_857) ) { cfsetispeed( &new_options, B38400 ); cfsetospeed( &new_options, B38400 ); } /* Set options for 'raw' I/O mode */ new_options.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON ); new_options.c_oflag &= ~( OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET ); new_options.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN ); new_options.c_cflag &= ~( CSIZE | PARENB ); new_options.c_cflag |= ( CS8 | CLOCAL | CREAD | CSTOPB ); /* Setup read() timeout to .2 sec */ new_options.c_cc[ VMIN ] = 0; new_options.c_cc[ VTIME ] = 2; /* Setup the new options for the port */ tcsetattr( tcvr_serial_fd, TCSAFLUSH, &new_options ); /* Enable CAT */ if( isFlagSet(ENABLE_CAT) ) Write_Tcvr_Command(CAT_ON); /* Test the serial port */ Write_Tcvr_Command( RX_STATUS ); Read_Tcvr_Serial( &test, 1 ); if( isFlagClear(SERIAL_IO_ERROR) ) Set_Flag( CAT_SETUP ); else { tcsetattr( tcvr_serial_fd, TCSANOW, &tcvr_serial_old_options ); close( tcvr_serial_fd ); tcvr_serial_fd = 0; } } /* End of Open_Tcvr_Serial() */ /*-------------------------------------------------------------------------*/ /* Read_Tcvr_Serial() * * Reading Data from the Tcvr's Serial Port */ void Read_Tcvr_Serial( unsigned char *cmnd, int block_size ) { /* Error condition */ if( read(tcvr_serial_fd, cmnd, block_size) < block_size ) { tcflush( tcvr_serial_fd, TCIOFLUSH ); Set_Flag( SERIAL_IO_ERROR ); Error_Dialog( "Serial port Rx I/O error" ); } } /* End of Read_Tcvr_Serial() */ /*-------------------------------------------------------------------------*/ /* Write_Tcvr_Command() * * Writes a command (status change) * to the Yaesu Tranceiver */ void Write_Tcvr_Command( unsigned char *cmnd ) { tcflush( tcvr_serial_fd, TCIOFLUSH ); if( write( tcvr_serial_fd, cmnd, 5 ) < 5 ) /* Error condition */ { tcflush( tcvr_serial_fd, TCIOFLUSH ); Set_Flag( SERIAL_IO_ERROR ); Error_Dialog( "Serial port Tx I/O error" ); return; } /* Give time to CAT to do its thing */ usleep(1000); } /* End of Write_Tcvr_Command() */ /*-------------------------------------------------------------------------*/ /* Close_Tcvr_Serial() * * Restore old options and close the Serial port */ void Close_Tcvr_Serial( void ) { if( isFlagSet(CAT_SETUP) ) { if( isFlagSet(ENABLE_CAT_847) ) Write_Tcvr_Command( CAT_OFF ); tcsetattr( tcvr_serial_fd, TCSANOW, &tcvr_serial_old_options ); close( tcvr_serial_fd ); tcvr_serial_fd = 0; } Clear_Flag( CAT_SETUP ); } /* End of Close_Tcvr_Serial() */ /*-------------------------------------------------------------------------*/ /* Tune_Tcvr() * * Tunes the transceiver to the frequency of the strongest * signal near a mouse click in the waterfall window */ void Tune_Tcvr( double x ) { int from, to, /* Range to scan for a max bin value */ bin_max, /* Max bin value found in this range */ max_idx, /* fft idx at which the max is found */ fft_idx, /* Idx used to search fft bin values */ tcvr_freq, /* Transceiver's Rx frequency */ audio_freq; /* Audio frequency in waterfal window */ /* Calculate fft index corresponding to pointer x in waterfall window */ fft_idx = (((int)(x-0.5))*FFT_SIZE) / (2*WFALL_WIDTH); /* Look above and below click point for max bin val */ from = fft_idx - 10; if( from < 0 ) from = 0; to = fft_idx + 10; if( to >= FFT_SIZE/2 ) to = FFT_SIZE/2; /* Find max bin value around click point */ bin_max = 0; max_idx = fft_idx; for( fft_idx = from; fft_idx < to; fft_idx++ ) if( bin_max < gbl_bin_ave[fft_idx] ) { bin_max = gbl_bin_ave[fft_idx]; max_idx = fft_idx; } /* Audio freq. corresponding to fft index */ audio_freq = (2 * max_idx * rc_data.tone_freq) / WFALL_WIDTH; /* Read current Rx frequency */ tcvr_freq = Read_Rx_Freq(); /* Calculate and write Rx freq. to center audio on AUDIO_FREQUENCY */ Write_Rx_Freq(tcvr_freq + audio_freq - rc_data.tone_freq); } /* Tune_Tcvr() */ /*-------------------------------------------------------------------------*/ /* Read_Rx_Freq() * * Reads the Rx freq of the Yaesu transceiver. */ int Read_Rx_Freq( void ) { /* A 5-char string for sending and receiving */ /* 5-byte strings to and from the transceiver */ unsigned char cmnd_parm[5]; int freq; bzero( cmnd_parm, 5 ); /* Abort if CAT disabled */ if( isFlagClear(CAT_SETUP) ) return(-1); /* Read Rx frequency */ Write_Tcvr_Command( MAIN_VFO ); if( isFlagSet(SERIAL_IO_ERROR) ) return(-2); Read_Tcvr_Serial( cmnd_parm, 5 ); if( isFlagSet(SERIAL_IO_ERROR) ) return(-3); /* Decode frequency data to 10Hz */ freq = 0; freq += (cmnd_parm[0] & 0xF0) >> 4; freq *= 10; freq += cmnd_parm[0] & 0x0F; freq *= 10; freq += (cmnd_parm[1] & 0xF0) >> 4; freq *= 10; freq += cmnd_parm[1] & 0x0F; freq *= 10; freq += (cmnd_parm[2] & 0xF0) >> 4; freq *= 10; freq += cmnd_parm[2] & 0x0F; freq *= 10; freq += (cmnd_parm[3] & 0xF0) >> 4; freq *= 10; freq += cmnd_parm[3] & 0x0F; freq *= 10; freq += (cmnd_parm[4] & 0xF0) >> 4; return( freq ); } /* End of Read_Rx_Freq() */ /*------------------------------------------------------------------------*/ /* Write_Rx_Freq() * * Writes the Rx freq to the Yaesu FT-847 transceiver. */ void Write_Rx_Freq( int freq ) { /* A 5-char string for sending and receiving */ /* 5-byte strings to and from the transceiver */ unsigned char cmnd_parm[5]; /* Buffer used for converting freq. to string */ char freq_buff[9]; int idx; /* Index for loops etc */ bzero( cmnd_parm, 5 ); /* Set Rx frequency */ snprintf( freq_buff, 9, "%08d", freq/10 ); for( idx = 0; idx < 4; idx++ ) { cmnd_parm[idx] = (freq_buff[2*idx] - '0') << 4; cmnd_parm[idx] |= (freq_buff[2*idx+1] - '0'); } cmnd_parm[4] = WRITE_RX_VFO; Write_Tcvr_Command( cmnd_parm ); } /* End of Write_Rx_Freq() */ /*-------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/Makefile.am0000644000175000017500000000100010772435546015261 0ustar pg4ipg4i## Process this file with automake to produce Makefile.in INCLUDES = \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ @PACKAGE_CFLAGS@ bin_PROGRAMS = xdemorse xdemorse_SOURCES = \ main.c xdemorse.h \ cat.c xdemorse.h \ detect.c detect.h \ decode.c xdemorse.h \ display.c xdemorse.h \ fft.c xdemorse.h \ sound.c xdemorse.h \ support.c support.h \ interface.c interface.h \ callbacks.c callbacks.h xdemorse_LDADD = @PACKAGE_LIBS@ xdemorse-1.3.orig/src/decode.c0000644000175000017500000002060410772715723014625 0ustar pg4ipg4i/* 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() */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/support.h0000644000175000017500000000372211111311621015076 0ustar pg4ipg4i/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include /* * Standard gettext macros. */ #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (PACKAGE, String) # define Q_(String) g_strip_context ((String), gettext (String)) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define Q_(String) g_strip_context ((String), (String)) # define N_(String) (String) #endif /* * Public Functions. */ /* * This function returns a widget in a component created by Glade. * Call it with the toplevel widget in the component (i.e. a window/dialog), * or alternatively any widget in the component, and the name of the widget * you want returned. */ GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name); /* Use this function to set the directory containing installed pixmaps. */ void add_pixmap_directory (const gchar *directory); /* * Private Functions. */ /* This is used to create the pixmaps used in the interface. */ GtkWidget* create_pixmap (GtkWidget *widget, const gchar *filename); /* This is used to create the pixbufs used in the interface. */ GdkPixbuf* create_pixbuf (const gchar *filename); /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description); xdemorse-1.3.orig/src/sound.c0000644000175000017500000002200510772450054014520 0ustar pg4ipg4i/* sound.c * * Soundcard handling functions of xdemorse application */ /* * xdemorse: An application to decode and display * Morse code signals using a computer's sound card * * 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" extern int dsp_fd, /* File descriptor of DSP device */ mix_fd; /* File descriptor of mixer device */ /* fft in buffer */ extern int *fft_in_r; /* Runtime config data */ extern rc_data_t rc_data; /*------------------------------------------------------------------------*/ /* Setup_Sound_Card() * * Sets up mixer and DSP devices */ gboolean Setup_Sound_Card( void ) { int new_recsrc, /* New recording source (RECORD_SRC) */ dsp_speed, /* DSP sampling speed as in xdemorse.h */ frag_size, /* DSP buffer (fragment) size in kb */ level, /* Rec/Volume level request to mixer */ num_chan, /* Stereo(=2) or Mono(=1) selection */ sample_fmt, /* DSP sample format, 8-bit unsigned */ itmp; /* Mixer device to be set-up (input or reclev) */ unsigned int device; /* Error messages */ char message[90]; /* Sound device names from souncard.h */ char *dev_name[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; /* File lock information */ struct flock lockinfo; /*** Open and lock mixer and dsp devices ***/ /* Open mixer device, abort on error */ if( (mix_fd = open(rc_data.mix_dev, O_RDONLY, 0)) == -1 ) { perror( rc_data.mix_dev ); snprintf( message, 90, "Unable to open mixer device %s\n" "Quit and correct xdemorserc", rc_data.mix_dev ); Error_Dialog( message ); return(FALSE); } /* Attempt to lock entire mixer device file */ lockinfo.l_type = F_RDLCK; lockinfo.l_whence = SEEK_SET; lockinfo.l_start = 0; lockinfo.l_len = 0; /* If mixer device is already locked, abort */ if( fcntl( mix_fd, F_SETLK, &lockinfo ) < 0 ) { perror( rc_data.mix_dev ); fcntl( mix_fd, F_GETLK, &lockinfo ); fprintf( stderr, "xdemorse: Lock %s: Device is locked by pid %d\n", rc_data.mix_dev, lockinfo.l_pid ); snprintf( message, 90, "Unable to lock %s\n" "Device locked by pid %d\n" "Quit and correct xdemorserc", rc_data.mix_dev, lockinfo.l_pid ); Error_Dialog( message ); return(FALSE); } /* Open DSP device, abort on error */ if( (dsp_fd = open(rc_data.dsp_dev, O_RDONLY, 0)) == -1 ) { perror( rc_data.dsp_dev ); snprintf( message, 90, "Unable to open dsp device %s\n" "Quit and correct xdemorserc", rc_data.dsp_dev); Error_Dialog( message ); return(FALSE); } /* Attempt to lock entire DSP device file */ lockinfo.l_type = F_RDLCK; lockinfo.l_whence = SEEK_SET; lockinfo.l_start = 0; lockinfo.l_len = 0; /* If DSP device is already locked, abort */ if( fcntl( dsp_fd, F_SETLK, &lockinfo ) < 0 ) { perror( rc_data.dsp_dev ); fcntl( dsp_fd, F_GETLK, &lockinfo ); fprintf( stderr, "xdemorse: Lock %s: Device is locked by pid %d\n", rc_data.dsp_dev, lockinfo.l_pid ); snprintf( message, 90, "Unable to lock %s\n" "Device locked by pid %d" "Quit and correct xdemorserc", rc_data.dsp_dev, lockinfo.l_pid ); Error_Dialog( message ); return(FALSE); } /*** Setup sound card parameters ***/ /* Find number of recording source matching source name */ for( new_recsrc = 0; new_recsrc < SOUND_MIXER_NRDEVICES; new_recsrc++ ) if( strcmp( dev_name[new_recsrc], rc_data.rec_src ) == 0 ) break; /* Make recording source mask */ itmp = 1 << new_recsrc; /* Attempt to select recording source, abort on error */ if( ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &itmp) == -1 ) { perror("xdemorse: SOUND_MIXER_WRITE_RECSRC"); snprintf( message, 90, "Failed to select Recording\n" "Source: %s\n" "Quit and correct xdemorserc", rc_data.rec_src ); Error_Dialog( message ); return(FALSE); } if( itmp != 1 << new_recsrc ) { snprintf( message, 90, "Failed to select Recording\n" "Source: %s\n" "Quit and correct xdemorserc", rc_data.rec_src ); Error_Dialog( message ); return(FALSE); } /* Zero level of recording source to silence (my) speakers */ level = 0; if( ioctl(mix_fd, MIXER_WRITE(new_recsrc), &level) == -1 ) { perror("xdemorse: Setting Recording source level"); snprintf( message, 90, "Failed to set %s level\n" "Quit and correct xdemorserc", rc_data.rec_src ); Error_Dialog( message ); return(FALSE); } if( level != 0 ) { snprintf( message, 90, "Failed to set %s level\n" "Quit and correct xdemorserc", rc_data.rec_src ); Error_Dialog( message ); return(FALSE); } /* Find recording level device */ for( device = 0; device < SOUND_MIXER_NRDEVICES; device++ ) if( strcmp( dev_name[device], rc_data.inp_lev ) == 0 ) break; if( device == SOUND_MIXER_NRDEVICES ) { snprintf( message, 90, "Failed to select Recording\n" " Level device: %s\n" "Quit and correct xdemorserc", rc_data.inp_lev ); Error_Dialog( message ); return(FALSE); } /* Write recording level to mixer, abort on error */ level = itmp = rc_data.rec_lev | (rc_data.rec_lev << 8); if( ioctl(mix_fd, MIXER_WRITE(device), &level) == -1 ) { perror("xdemorse: Setting Recording level"); Error_Dialog( "Failed to set Recording level\n" "Quit and correct xdemorserc" ); return(FALSE); } if( level != itmp ) { Error_Dialog( "Failed to set Recording level\n" "Quit and correct xdemorserc" ); return(FALSE); } /* Set fragment size according to stereo/mono mode */ itmp = 1; frag_size = 0; num_chan = rc_data.num_chn; while( (itmp << frag_size) != BUFFER_SIZE ) frag_size++; itmp += num_chan << 18; ioctl( dsp_fd, SNDCTL_DSP_SETFRAGMENT, &frag_size ); /* Set sample format to unsigned 8-bit, abort on error */ sample_fmt = AFMT_U8; if( ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &sample_fmt) == -1 ) { perror( "xdemorse: SNDCTL_DSP_SETFMT"); Error_Dialog( "Failed to set dsp format: AFMT_U8\n" "Quit and correct xdemorserc" ); return(FALSE); } if( sample_fmt != AFMT_U8 ) { Error_Dialog( "Failed to set dsp format: AFMT_U8\n" "Quit and correct xdemorserc" ); return(FALSE); } /* Set stereo/mono mode */ itmp = num_chan; if( ioctl(dsp_fd, SNDCTL_DSP_CHANNELS, &itmp) == -1 ) perror("SNDCTL_DSP_CHANNELS"); /* Setup DSP sampling speed, abort on error */ dsp_speed = rc_data.dsp_speed; if( ioctl(dsp_fd, SNDCTL_DSP_SPEED, &dsp_speed) == -1 ) { perror( "xdemorse: SNDCTL_DSP_SPEED"); snprintf( message, 90, "Failed to set DSP speed to %d\n" "Quit and correct xdemorserc", rc_data.dsp_speed ); Error_Dialog( message ); return(FALSE); } if( dsp_speed != rc_data.dsp_speed ) { snprintf( message, 90, "Failed to set DSP speed to %d\n" "Quit and correct xdemorserc", rc_data.dsp_speed ); Error_Dialog( message ); return(FALSE); } return( TRUE ); } /* End of Setup_Sound_Card() */ /*------------------------------------------------------------------------*/ /* Get_Signal_Sample() * * Gets the next DSP sample of the signal input */ int Signal_Sample(void) { /* Number of samples read from dsp */ int sample_cnt; static int fft_idx = 0, /* fft input buffer idx */ cnt = 0; /* Count of calls to this function */ /* New DSP sample of audio input */ int sample; /* Refill dsp samples buffer when needed */ if( rc_data.buffer_idx >= rc_data.buffer_size ) { /* Start buffer index according to stereo/mono mode */ if( rc_data.num_chn == 1 ) /* Mono */ rc_data.buffer_idx = 0; else rc_data.buffer_idx = rc_data.use_chn; /* Read audio samples from DSP, abort on error */ if( (sample_cnt = read(dsp_fd, rc_data.buffer, rc_data.buffer_size)) == -1 ) { perror( "xdemorse: dsp read()" ); Error_Dialog( "Error reading from dsp device\n" "Quit xdemorse and correct" ); Set_Flag( DSP_IO_ERROR ); } if( sample_cnt != rc_data.buffer_size ) { Error_Dialog( "Error reading from dsp device\n" "Quit xdemorse and correct" ); Set_Flag( DSP_IO_ERROR ); } } /* End of if( buffer_idx >= buffer_size ) */ /* Remove neutral value (128) from samples */ sample = rc_data.buffer[ rc_data.buffer_idx ] - 128; /* Display waterfall when input buffer full */ /* rc_data.fft_stride samples added for each input element */ if( cnt == 0 ) fft_in_r[fft_idx] = sample; else fft_in_r[fft_idx] += sample; if( ++cnt >= rc_data.fft_stride ) { fft_idx++; cnt = 0; } if( fft_idx >= FFT_SIZE ) { fft_idx = 0; Display_Waterfall(); } /* Increment according to mono/stereo mode */ rc_data.buffer_idx += rc_data.num_chn; return( sample ); } /* End of Get_Signal_Sample() */ /*------------------------------------------------------------------------*/ xdemorse-1.3.orig/src/detect.h0000644000175000017500000000235010772437702014653 0ustar pg4ipg4i/* detect.h * * Header file for detect.c */ /* * xdemorse: An application to decode Morse signals to text * * Copyright (C) 2001 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 */ #ifndef DETECT_H #define DETECT_H 1 /* Buffers and data needed by tone detector */ struct detector_data { int frag_len, samples_buff_len, /* Length of DSP samples buffer */ samples_buff_idx; /* Sample buffer index */ /* Circular signal level buffer and index for edge detector */ int sig_level_idx, *sig_level_buff; /* Variables for the Goertzel algorithm */ double cosw, sinw, coeff; /* Circular signal samples buffer for Goertzel detector */ char *samples_buff; } detector_data; #endif /* End of detect.h */ xdemorse-1.3.orig/src/xdemorse.h0000644000175000017500000001661110772752136015237 0ustar pg4ipg4i/* xdemorse.h * * Header file for xdemorse */ /* * xdemorse: An application to decode Morse signals to text * * Copyright (C) 2001 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 */ #ifndef XDEMORSE_H #define XDEMORSE_H 1 #include #include #include #include #include #include #include #include #include #include #include /************ CUSTOMIZE THESE DEFINITIONS FOR YOUR NEEDS *************/ /* Definitions for Morse code conversion to ascii */ #define NUMBER_OF_CHAR 55 /* Number of chars in ASCII table */ /* ASCII equivalents to Morse hex code. Last */ /* one (*) used for unrecognized characters. */ #define MORSE_ASCII_CHAR \ { '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', \ '1','2','3','4','5','6','7','8','9','0','.',',',':', \ '?','\'','-','/','(','"',';','$','#','<','!','@',']',\ '=','~',' ','*' } /* Hex equivalents to Morse code chars above except (*). */ /* Formed by starting with a 1 and following with a 0 for */ /* dash and 1 for dit e.g: A = ditdah = 101 = Hex 0x06. */ #define MORSE_HEX_CODE \ { 0x06,0x17,0x15,0x0b,0x03,0x1d,0x09,0x1f,0x07,0x18,0x0a,0x1b,0x04,\ 0x05,0x08,0x19,0x12,0x0d,0x0f,0x02,0x0e,0x1e,0x0c,0x16,0x14,0x13,\ 0x30,0x38,0x3c,0x3e,0x3f,0x2f,0x27,0x23,0x21,0x20,0x6a,0x4c,0x47,\ 0x73,0x61,0x5e,0x2d,0x52,0x6d,0x55,0xf6,0x35,0x7a,0x2a,0x37,0x29,\ 0x2e,0xff,0x01 } /***************** END OF CUSTOMIZABLE SECTION ***********************/ /* Signal Detector parameter definitions */ #define BUFFER_SIZE 1024 /* Size of buffer for signal samples */ #define WFALL_WIDTH 256 /* Width of Waterfall drawingarea */ #define CYCLES_PER_FRAG 2 /* Cycles of signal/signal fragment */ #define BINMAX_AVE_WIN 5 /* Length of bin max averaging window */ #define FFT_SIZE 512 /* Size of fft input/output arrays */ #define FFT_SIZE2 256 /* Size/2 of fft input/output arrays */ #define GOERTZEL_SCALE 1024 /* Scale factor for integer Goertzel algorithm*/ #define STEP_THRESHOLD 105 /* % diff between successive sig levels */ #define MAX_SPEED 60 /* Maximum allowed Morse unit (dot) length */ #define MIN_SPEED 6 /* Minimum allowed Morse unit (dot) length */ /* Transceiver type */ #define FT847 1 #define FT857 2 #define NONE 0 /* Definitions of contexts (stages) in Morse decoding process */ #define MARK_SIGNAL 0x000001 /* Count fragments of a mark element */ #define ELEM_SPACE 0x000002 /* Count frag. of inter-element space */ #define CHAR_SPACE 0x000004 /* Count fragments of inter-char space */ #define WAIT_WORD_SPACE 0x000008 /* Wait for an inter-word space */ #define WORD_SPACE 0x000010 /* Count fragments of inter-word space */ #define WAIT_FOR_MARK 0x000020 /* Count fragments of no-signal space */ #define WAIT_FOR_SPACE 0x000040 /* Wait for a space after a long dash */ #define MARK_TONE 0x000080 /* Input signal is mark tone (key down)*/ /* Definitions of flags for various actions */ #define ADAPT_SPEED 0x000100 /* Enable speed tracking */ #define MAN_THRESHOLD 0x000200 /* Enable manual detector threshold */ #define WORD_WRAP 0x000400 /* Enable word wrapping */ #define DISPLAY_SIGNAL 0x000800 /* Display output of signal detector */ #define DISPLAY_DETECTOR 0x001000 /* Display output of signal detector */ #define DSP_IO_ERROR 0x002000 /* Error reading from dsp */ #define REVERSE_VIDEO 0x004000 /* Reverse waterfall video */ #define ENABLE_CAT 0x008000 /* Enable CAT for transceiver */ #define CAT_SETUP 0x010000 /* CAT is set up */ #define ENABLE_CAT_847 0x020000 /* Enable CAT for FT847 */ #define ENABLE_CAT_857 0x040000 /* Enable CAT for FT857 */ #define SERIAL_IO_ERROR 0x080000 /* Error occured in serial i/o */ #define LONG_SPACE 0x100000 /* Long period of space (no tone) */ #define ENABLE_RECEIVE 0x200000 /* Enable reception of Morse code */ /* Channel to be used in audio capture */ #define LEFT 0 /* Left channel */ #define RIGHT 1 /* Right channel */ /* Special characters */ #define LF 0x0A /* Line Feed */ #define CR 0x0D /* Carriage Return */ #define HT 0x09 /* Horizontal Tab */ /* Return values */ #define ERROR 1 /* Error condition */ #define SUCCESS 0 /* No error condition */ /*-------------------------------------------------------------------*/ /* Runtine configuration data */ typedef struct { char mix_dev[21], /* Mixer device name */ dsp_dev[21], /* DSP device name */ rec_src[21], /* Recording/capture source */ inp_lev[21]; /* Input level contol name */ /* Transceiver serial devices */ char ft847_serial[32], ft857_serial[32]; /* Transceiver type 1=FT847 2=FT867 0=NONE */ int tcvr_type; int num_chn, /* Number of audio channels (2=stereo, 1=mono) */ use_chn, /* Channel in use: 0=left, 1=right */ rec_lev, /* Recording/Capture level */ dsp_speed; /* DSP speed samples/sec */ int tone_freq, /* Receiver BFO Tone freq */ red_line, /* Waterfall BFO Tone freq marker line */ fft_stride; /* Stride of fft over input samples */ int unit_elem, /* Morse unit element (dot) length */ max_unit, /* Maximum length of unit element */ min_unit, /* Minimum length of unit element */ spd_wpm, /* Current Morse speed words/min */ wrd_wrp, /* Maximum line length if word wrap enabled */ det_thr; /* Signal threshold for Mark/Space separation */ /* Signal/dsp samples buffer */ unsigned char *buffer; int buffer_idx, /* Index to signal samples buffer */ buffer_size; /* Buffer size according to stereo/mono mode */ } rc_data_t; /*-------------------------------------------------------------------*/ /* Function prototypes produced by cproto */ /* callbacks.c */ void Error_Dialog(char *message); /* cat.c */ void Open_Tcvr_Serial(void); void Read_Tcvr_Serial(unsigned char *cmnd, int block_size); void Write_Tcvr_Command(unsigned char *cmnd); void Close_Tcvr_Serial(void); void Tune_Tcvr(double x); int Read_Rx_Freq(void); void Write_Rx_Freq(int freq); /* decode.c */ char Get_Character(void); void Adapt_Decoder(void); char Hex_to_Ascii(int *hex_code); /* detect.c */ int Get_Fragment(void); gboolean Initialize_Detector( void ); /* display.c */ void Display_Detector(int plot); void Display_Signal(int plot); void Display_Waterfall(void); void Clear_Pixbuf(void); /* fft.c */ void Ifft_init(int fft_size); void Ifft(int fft_size); gboolean mem_alloc(void **ptr, int req); /* main.c */ int main(int argc, char *argv[]); gboolean Print_Character(gpointer data); int Load_Line(char *buff, FILE *pfile, char *messg); gboolean Load_Config(gpointer data); void Usage(void); int isFlagSet(int flag); int isFlagClear(int flag); void Set_Flag(int flag); void Clear_Flag(int flag); void Toggle_Flag(int flag); void Cleanup(void); /* sound.c */ gboolean Setup_Sound_Card(void); int Signal_Sample(void); #endif /* End of xdemorse.h */