





Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
The source code for a morse code teaching machine, written in c. The program sends morse code characters to the pc speaker and waits for the student to press the corresponding key. If the student takes too much time, the program gives a hint and resends the character until the student finally gets the answer right. The student is graded on his performance. The probability of choosing a letter is proportional to the estimated error rate for that letter.
Typology: Exercises
1 / 9
This page cannot be seen from the preview
Don't miss anything!






/*** morse - an automatic morse code teaching machine /* /* Copyright (c) 1978 Howard Cunningham all rights reserved /* Copyright (c) 1988 Jim Wilson /* /* Revision History: 04/18/78 initial pascal version adapted from 8080 /* 12/04/81 corrected typo (div for mod in select) /* 06/18/88 translated to C /* 07/14/98 corrected accelerated character introduction /* omitted in translation to C /* /* Reference: "A Fully Automatic Morse Code Teaching Machine", /* QST, (May 1977), ARRL, Newington CT */ #include <stdio.h>
/*** tweekable parameters and magic numbers */
#define WPM 15 /* Initial codespeed in words-per-minute / #define isdah(c) (c&1) / Mask l.s.b. to test dot or dash / #define TONE_ON 1162 / Period in microseconds (1Khz) / #define TONE_OFF 0 / Special value for silent period / #define NLINE 25 / Number of lines on PC screen and / #define LINLEN 72 / number of characters on each line / #define BARHT (NLINE-6) / Maximum height of error rate bars / #define GOOD 0 / The best one can do / #define BAD 255 / The worst one can do / #define DIT(wpm) (1395/(wpm)) / Dit length for beep() - roughly in mS / #define BRGRY 176 / Bargraph character for inactive letters / #define BRCHR 219 / Bargraph character for active latters */
/*** display character attributes for various screen regions
#define CWIN 0x0700 /* Code window, white on black */
/*** external functions from beep.s or the C runtime library */
extern srand(), rand(); /* seed, return random number (in C runtime) / extern beep(); / Sound tone for an interval (in beep.s) / extern unsigned ticks(); / Return mS since last call (in beep.s) / extern char resp(); / nonblocking keyboard input (in beep.s) / extern unsigned tod(); / DOS raw time-of-day counter (for srand()) */
unsigned num = 2; /* Characters introduced so far (start with 2) / unsigned dit = DIT(20); / Default to 20 wpm */
/*** Letter[] holds character codes and error info for each letter /* MAXNUM is the largest size of the active alphabet. /* The 0th element is not part of the alphabet. It is used to /* store an overall error indication for convenient display. / #define MAXNUM (sizeof(letter)/sizeof(struct lt)-1) / maximum alphabet / #define OVERALL letter[0] / for easy graphing!! */
struct lt {char ascii; char morse; unsigned char error;} letter[] = { {'*', 0, GOOD}, {'Q', 033, BAD}, {'7', 043, BAD}, {'Z', 023, BAD}, {'G', 013, BAD}, {'0', 077, BAD}, {'9', 057, BAD}, {'8', 047, BAD}, {'O', 017, BAD}, {'1', 076, BAD}, {'J', 036, BAD}, {'P', 026, BAD}, {'W', 016, BAD}, {'L', 022, BAD}, {'R', 012, BAD}, {'A', 006, BAD}, {'M', 007, BAD}, {'6', 041, BAD}, {'B', 021, BAD}, {'X', 031, BAD}, {'D', 011, BAD}, {'Y', 035, BAD}, {'C', 025, BAD}, {'K', 015, BAD}, {'N', 005, BAD}, {'2', 074, BAD}, {'3', 070, BAD}, {'F', 024, BAD}, {'U', 014, BAD}, {'4', 060, BAD}, {'5', 040, BAD}, {'V', 030, BAD}, {'H', 020, BAD}, {'S', 010, BAD}, {'I', 004, BAD}, {'T', 003, BAD}, {'E', 002, BAD}, };
/*** main - teach morse code /* /* This program repeatedly selects a letter and teaches it to the /* student. The student can request an evaluation and/or terminate /* the session. */ main(int argc, char argv[]) { herald(); / Print program herald / srand(tod()); / seed random number generator / bgs(); / Show bargraph on screen / do { pms(CWIN, "\013\n\n\n\n"); / Clear code window / beep(TONE_OFF, 600); / Take a breath before we start / do ; while (teach(select())); / teach letters / } while (menu()); / grade and perhaps quit */ }
/*** herald - emit program proclamation
l = &letter[lesson]; /* Point register at lesson / answer = l->ascii; / Get solution to problem / score = GOOD; / Assume the best / do { if (column <= 0) { / If at end-of-line / pc('\n'+CWIN); / output newline and / column = LINLEN; / rearm counter / } send(l->morse); / Send Morse character. / while (guess = resp()) / Flush typeahead, but / if (guess == '\r') / if student want's a break, / return column = 0; / grant the wish / ticks(); time = 0; / Reset stopwatch. / do { / Loop to wait for answer: / guess = resp(); / Get student response (if any) / if (guess == answer) / If correct answer, / break; / stop and update gradebook / if (guess == '\r') / If student wants break, reset column / return column = 0; / count (for next lesson), return / time += ticks(); / Add elapsed time / } while (time <= give); / Stop if student too slow / if (guess != answer) / If ever time out w.o. correct / score = BAD; / answer, deduct some points / pc(answer+CWIN); / Echo correct answer / pc(' '+CWIN); column -= 2; / and adorn it with a blank / give = weight(give, 2time);/* Update response time / if (give>6000) give = 6000; / (but limit to 5-6 S.) / beep(TONE_OFF, 250); / Wait a brief interval / } while (guess != answer); grade(lesson, score); / Update gradebook */
/* Student has answered correctly, so we'll give her some more.
/*** send - send charcter in morse code /* /* Send() is passed a morse coded letter (see reference). /* It sends the character at speed "WPM" on the PC's speaker. /* /* Calling Sequence: send(morse); /* /* where (char) "morse" is a stop-bit-prepended morse character. */ send(char code) {
register element; do { element = dit; if (isdah(code)) element *= 3; beep(TONE_ON, element); beep(TONE_OFF, dit); } while ((code >>= 1) != 1); }
/*** select - choose a letter from the current alphabet /* /* Select() returns the index of a letter chosen from the /* currently active alphabet. The probability of chosing /* a letter is proportional to the estimated error rate /* for that letter. /* /* Calling Sequence: new_letter = select(); /* /* where (int) "new_letter" is the index of the chosen element /* from letter[]. / select() { register int sum; / error probability accumulator / register int l; / working index into letter[] */
sum = 0; l = 1; do { sum += letter[l++].error + 1; } while (l <= num); sum = rand() % sum; do { sum -= letter[--l].error + 1; } while (sum > 0); return (l); }
/*** menu - display 4-line menu, one-line prompt, and get choice /* /* Menu() displays a simple 4-line menu, and prompts for a selection. /* It awaits a valid choice and acts on it. It returns nonzero or /* zero when "C(ontinue)" or "Q(uit)" are selected (respectively). /* /* Calling Sequence: int menu(); / menu() { pms(CWIN, / NOTE: Change showspd(), below, if you change menu!!! / "\nCharacter Code Speed:\203Practice Alphabet:\206Training:\n" "\202S(low --- 10 wpm)\207A(dd another letter)\203C(ontinue training)\n" "\202M(edium - 15 wpm)\207R(emove last letter)\203Q(uit program)\n" "\202F(ast --- 20 wpm)\nYour choice? (SMFARCQ): "); showspd(); / Show codespeed (see NOTE, above) */ for (;;) switch (resp()) {
/* Calling Sequence: pms(int attribute, char *message); */ pms(int attr, char *msg) { register int c; register int i; while (c = msg++) { / While more message left to display, / if (c & 0x80) { / If compressed blank, / for (c &= 0x7F; c; c--)/ display a sequence of blanks / pc(attr+' '); } / If other character, / else pc(attr+c); / Let the low-level code handle it */ } }
/*** barht - convert score (in [0,BAD]) to bar graph height /* /* Barht() is passed an integer error rate in [0,BAD]. It linearly /* scales this value to [0,BARHT], the number of illuminated lines /* in a crude bar graph displayed in a column on the screen. /* /* Calling Sequence: int barht(int score); / barht(int score) { return (scoreBARHT + BAD/2)/BAD; }
/*** grade - update error estimates /* /* Grade() is passed an index to the current letter and GOOD /* if the student got the right answer or BAD if she had to /* be told the answer. Grade() updates the particular and /* overall error rate estimates and revises the displayed /* bargraph to display the change. /* /* Calling sequence: grade(ltr, grade); /* /* where (int) "ltr" is the index of the current letter /* and (int) "grade" is GOOD or BAD. / grade(unsigned ltr, unsigned g) { / Index to lesson, test results / register struct lt l; / Pointer to element being dated / int old, new; / Old, bar first display row / l = &letter[ltr]; / Aim register into letter[] / ltr = (ltr-1)2; / Ltr = column in bargraph / old = BARHT - barht(l->error); / 1st row that now has a bar / update(l, g); / Update specific error rate / if (update(&OVERALL, g) < BAD * 1/10) / If overall error rate low, / update(l, g); / accelerate specific rate / new = BARHT - barht(l->error); / 1st row that SHOULD have bar / while (new != old) { / Until graph bar is right sized, / if (new > old) / If too tall, */
prc(' ' +NORM, old++, ltr); /* chop it down to size / else / If too short, / prc(BRCHR+NORM, --old, ltr); / build it up a bit */ } }
/*** update - update error rate /* /* Update() is passed the address of an element of letter[], and a grade /* (either GOOD or BAD). It updates the .error probability estimate /* field, and returns the new value for this field. /* /* Calling sequence: int update(struct lt *ltr, int grade); */ update(struct lt *l, unsigned g) { return l->error = weight(l->error, g); }
/*** bgs - display (initial) bargraph on screen /* /* Bgs() erases the herald display (see herald(), above), and replaces /* it with a crude bargraph of the student's error rate (i.e. the /* letter[].error fields). Below each bar, the corresponding letter /* (i.e. the letter[].ascii) is displayed. Active letters are dis- /* tinguished by displaying their bargraph as a solid bar; inactive /* letters' bars are "greyed". /* /* Calling Sequence: bgs(); / bgs() { register int i = 0; / Index into letter[] / pc('\f'+NORM); / Clear screen / do drwbar(++i); / Draw bargraph */ while (i < MAXNUM); }
/*** add_ltr, rem_ltr - add letter/remove letter from training aphabet /* /* Add_ltr() checks "num", the number of letters in the training alphabet /* and increases it (assuming it is not maxed out already). The appear- /* ance of the new character (its bargraph bar) is redrawn as solid to /* reflect its new status. /* /* Rem_ltr() decreases the number of letters, (but not less than 1) and /* "greys" the bargraph appropriately. /* /* Calling Sequence: add_ltr(); ... rem_ltr(); / add_ltr() { if (num < MAXNUM) drwbar(++num); } / Room to add? redraw bar / rem_ltr() { if (num > 1) drwbar(num--); } / More than 1? redraw bar */
/*** drwbar - draw bargraph bar