home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / MORSE.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  8KB  |  242 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*
  4. **   <<< Morse Code Functions >>>
  5. ** 
  6. ** Written by Michael M. Dodd, N4CF, and placed in the public domain.
  7. ** 
  8. ** The morse() function transmits a string in Morse code on the IBM PC's
  9. ** speaker.  The speed is set by a program constant (UNIT_TIME).
  10. ** 
  11. ** There are several other functions in this file, all used by morse(),
  12. ** and defined ahead of morse() for convenience.
  13. ** 
  14. ** The main() function at the end of the file is a test program to send
  15. ** the command-line argument string in morse code.  Enclose multiple
  16. ** words in quotes.  Example:  morse "hello, world"
  17. ** 
  18. ** These functions have been compiled and tested in the Small and Large
  19. ** memory models using Microsoft C 6.00a.
  20. **
  21. ** Modified for ZTC++, TC++, & BC++ by Bob Stout
  22. */
  23.  
  24. #include <stdio.h>
  25. #include <dos.h>
  26. #include <conio.h>
  27. #include <ctype.h>
  28.  
  29. /*
  30. ** These functions turn on and off the CW tone on the PC's speaker.  The
  31. ** frequency is specified by the freq argument.
  32. ** IMPORTANT!  These functions are highly IBM PC-specific!
  33. */
  34.  
  35. #define CLK_FREQ (1193180L)
  36. #define PIO (0x61)
  37. #define CTC_CMD (0x43)
  38. #define CTC_DATA (0x42)
  39. #define SETUP (0xB6)
  40. #define TONE_ON (0x03)
  41. #define TONE_OFF (0xFC)
  42.  
  43. void note_on (int freq)        /* Turn on the tone.  */
  44. {
  45.       int divisor ;
  46.       int pio_word ;
  47.  
  48.       divisor = (int)(CLK_FREQ / (long)(freq)) ;
  49.       outp (CTC_CMD, SETUP) ;
  50.       outp (CTC_DATA, divisor & 0xFF) ;
  51.       outp (CTC_DATA, divisor >> 8) ;
  52.       pio_word = inp (PIO) ;
  53.       outp (PIO, pio_word | TONE_ON) ;
  54. }
  55.  
  56. void note_off (void)           /* Turn off the tone.  */
  57. {
  58.       int pio_word ;
  59.  
  60.       pio_word = inp (PIO) ;
  61.       outp (PIO, pio_word & TONE_OFF) ;
  62. }
  63.  
  64. /*
  65. ** These functions implement a timing-loop delay.  Because the PC's
  66. ** internal clock is too coarse for accurate CW timing, the pause()
  67. ** function uses a simple software loop to produce a delay.
  68. ** 
  69. ** To minimize the effects of CPU clock speed, the calib() function
  70. ** returns a number which represents a rough index of the clock speed
  71. ** with relation to the standard IBM PC (this is very approximate).
  72. ** 
  73. ** Calibration is performed only once, when the static fudge_factor is
  74. ** zero.  Thereafter, the contents of fudge_factor are used to form a
  75. ** delay value.
  76. ** 
  77. ** IMPORTANT!  These functions are highly IBM PC-specific!
  78. */
  79.  
  80. unsigned int calib (void)
  81. {
  82.       unsigned int far *timerLow = (unsigned int far *)(0x046c) ;
  83.       unsigned int lastTime ;
  84.       unsigned int iter ;
  85.  
  86.       for (lastTime = *timerLow; lastTime == *timerLow;)
  87.             ;
  88.  
  89.       for (iter = 0, lastTime = *timerLow; lastTime == *timerLow; iter++)
  90.             ;
  91. #if   defined(__ZTC__)
  92.       return ((unsigned int)((125L * ((long)(iter)) + 50L) / 2300L)) ;
  93. #elif defined(__TURBOC__)
  94.       return ((unsigned int)((77L * ((long)(iter)) + 50L) / 2300L)) ;
  95. #else /* assume MSC */
  96.       return ((unsigned int)((100L * ((long)(iter)) + 50L) / 2300L)) ;
  97. #endif
  98. }
  99.  
  100. void pause (unsigned int amount)
  101. {
  102.       static unsigned int fudge_factor = 0 ;
  103.       unsigned long ul ;
  104.  
  105.       if (fudge_factor == 0)       /* Calibrate the speed.  */
  106.             fudge_factor = calib () ;
  107.  
  108.       ul = (unsigned long)(amount) * (long)(fudge_factor) ;
  109.       while (ul--)                 /* Delay.  */
  110.             ;
  111. }
  112.  
  113. /*
  114. ** These functions transmit a dot, a dash, a letter space, and a
  115. ** word space.
  116. ** 
  117. ** Note that a single unit space is automatically transmitted after
  118. ** each dot or dash, so the ltr_space() function produces only a
  119. ** two-unit pause.
  120. ** 
  121. ** Also, the word_space() function produces only a four-unit pause
  122. ** because the three-unit letter space has already occurred following
  123. ** the previous letter.
  124. */
  125.  
  126. #define SPACE_MASK (1 << 15)
  127. #define BIT_MASK (0xfe)
  128. #define UNIT_TIME (18)
  129. #define FREQUENCY (1500)
  130.  
  131. void send_dot (void)           /* Send a dot and a space.  */
  132. {
  133.       note_on (FREQUENCY) ;
  134.       pause (UNIT_TIME) ;
  135.       note_off () ;
  136.       pause (UNIT_TIME) ;
  137. }
  138.  
  139. void send_dash (void)          /* Send a dash and a space.  */
  140. {
  141.       note_on (FREQUENCY) ;
  142.       pause (UNIT_TIME * 3) ;
  143.       note_off () ;
  144.       pause (UNIT_TIME) ;
  145. }
  146.  
  147. void ltr_space (void)          /* Produce a letter space.  */
  148. {
  149.       pause (UNIT_TIME * 2) ;
  150. }
  151.  
  152. void word_space (void)         /* Produce a word space.  */
  153. {
  154.       pause (UNIT_TIME * 4) ;
  155. }
  156.  
  157.  
  158. /*
  159. ** MORSE () - Transmit a string in Morse code
  160. ** 
  161. ** This function transmits the string pointed to by the cp argument in
  162. ** Morse code on the PC's speaker.  The speed is set by the UNIT_TIME
  163. ** constant.
  164. ** 
  165. ** A static table translates from ASCII to Morse code.  Each entry is
  166. ** an unsigned integer, where a zero represents a dot and a one
  167. ** represents a dash.  No more than 14 bits may be used.  Setting bit
  168. ** 15 produces a word space, regardless of any other pattern.
  169. ** 
  170. ** The Morse code pattern is taken from bit 0, and is shifted right
  171. ** each time an element is sent.  A special "marker bit" follows the
  172. ** complete Morse pattern.  This marker bit is tested before
  173. ** transmitting each bit; if there are no 1's in bits 1..15, the
  174. ** complete character has been sent.
  175. ** 
  176. ** For example, an "L" would be 0000000000010010, with bit zero
  177. ** containing the first dot, bit one the dash, etc.  The marker
  178. ** bit is in bit 4.
  179. */
  180.  
  181. void morse (char *cp)
  182. {  /*--- MORSE CODE FUNCTION ---*/
  183.  
  184.       unsigned int c ;
  185.       static unsigned int codes [64] = {
  186.             SPACE_MASK,                      /* Entry 0 = space (0x20)  */
  187.             0, 0, 0, 0, 0, 0, 0, 0,          /* ! " # $  % & " (  */
  188.             0, 0, 0, 115, 49, 106, 41,       /* ) * + , - . /     */
  189.             63, 62, 60, 56, 48, 32, 33, 35,  /* 0 1 2 3 4 5 6 7   */
  190.             39, 47, 0, 0, 0, 0, 0, 76,       /* 8 9 : ; < = > ?   */
  191.             0, 6, 17, 21, 9, 2, 20, 11,      /* @ A B C D E F G   */
  192.             16, 4, 30, 13, 18, 7, 5, 15,     /* H I J K L M N O   */
  193.             22, 27, 10, 8, 3, 12, 24, 14,    /* P Q R S T U V W   */
  194.             25, 29, 19                       /* X Y Z  */
  195.             } ;
  196.  
  197.       pause (0) ;                  /* Calibrate pause() function.  */
  198.  
  199.       while ((c = *cp++) != '\0')
  200.       {  /*--- TRANSMIT COMPLETE STRING ---*/
  201.  
  202.             c = toupper (c) ;          /* No lower-case Morse characters.  */
  203.             c -= ' ' ;                 /* Adjust for zero-based table.  */
  204.  
  205.             if (c > 58)                /* If out of range, ignore it.  */
  206.                   continue ;
  207.  
  208.             c = codes[c] ;             /* Look up Morse pattern from table. */
  209.  
  210.             if (c & SPACE_MASK)        /* If the space bit is set..  */
  211.             {                          /* ..send a word space and go on.  */
  212.                   word_space () ;
  213.                   continue ;
  214.             }
  215.  
  216.             while (c & BIT_MASK)       /* Transmit one character.  */
  217.             {  /*--- TRANSMIT EACH BIT ---*/
  218.                   if (c & 1)
  219.                         send_dash () ;
  220.                   else  send_dot () ;
  221.  
  222.                   c >>= 1 ;
  223.             }  /*--- TRANSMIT EACH BIT ---*/
  224.  
  225.             ltr_space () ;             /* Send a space following character. */
  226.  
  227.       }  /*--- TRANSMIT COMPLETE STRING ---*/
  228.  
  229. }  /*--- MORSE CODE FUNCTION ---*/
  230.  
  231.  
  232. /*
  233. ** This is the test program, which transmits argv[1] in Morse code.
  234. */
  235.  
  236. main (int argc, char *argv[])
  237. {
  238.       while (--argc)
  239.             morse (*++argv) ;
  240.       return 0;
  241. }
  242.