cw2hex, 2 parts: Makefile, C source

Part 1: Unix Makefile
#
#	Makefile for cw2hex.c     WB0RIO
#	Known to work with SUN Solaris, Debian Linux
#

CC = gcc

CFLAGS = -Wall
LFLAGS = -lm

OBJS = cw2hex.o

cw2hex:	$(OBJS)
	$(CC) -o cw2hex $(CFLAGS) $(OBJS) $(LFLAGS)

clean:
	rm -f *.o core cw2hex




Part 2: C source

/*--------------------------------------------------------------*
 * Morse Code to Eprom Hex File Program cw2hex Version 1.2	*
 * Copyright G. Forrest Cook WB0RIO - 9/11/1996			*
 * Circuitry available at http://www.solorb.com/elect/		*
 * This code has been released under the			*
 * GNU GENERAL PUBLIC LICENSE version 2: http://www.gnu.org/	*
 *								*
 * This program takes a textual input and converts it to morse	*
 * encoded characters in the form of a standard Intel HEX file.	*
 * The Hex file can be used to program an EPROM which can then	*
 * be connected to a simple circuit that generates canned	*
 * messages.  Possible uses are CW calling machines and CW	*
 * beacon transmitter keyers.					*
 * Design note: this is far from an efficient user of EPROM	*
 * space, EEPROMs are cheap and even a 2K chip will hold a very	*
 * long message.						*
 *								*
 * The EPROM D0 output pin is the keyed line.			*
 * The EPROM D1 output pin is used to reset the counter in	*
 * continuous loop mode or to stop the counter in one time	*
 * mode.							*
\*--------------------------------------------------------------*/

#include <stdio.h>
#include <ctype.h>
#include <math.h>

#define HEXFILENAME "cw.hex"

/*
 * function declarations
 */
int outbyte();
void hexbout();
void hexwout();

FILE    *Hexfile=0;                 /* Hex file pointer */


int main ()
{
	char *cp, uc, instr[500];
	int i, j, len;
/*
 * This table contains the morse coded characters encoded into 1s and 0s.
 * The trailing 9 ends the current character.
 */
	static unsigned char morse[51][24]=
	{
		{1,0,1,1,1,0,0,0,0,9},			/* A */
		{1,1,1,0,1,0,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,0,1,0,0,0,0,9},
		{1,0,0,0,0,9},
		{1,0,1,0,1,1,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,1,1,0,1,0,0,0,0,9},
		{1,0,1,0,1,0,1,0,0,0,0,9},
		{1,0,1,0,0,0,0,9},
		{1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9},
		{1,1,1,0,1,0,1,1,1,0,0,0,0,9},
		{1,0,1,1,1,0,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,1,1,0,0,0,0,9},
		{1,1,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9},
		{1,0,1,1,1,0,1,1,1,0,1,0,0,0,0,9},
		{1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,9},
		{1,0,1,1,1,0,1,0,0,0,0,9},
		{1,0,1,0,1,0,0,0,0,9},
		{1,1,1,0,0,0,0,9},
		{1,0,1,0,1,1,1,0,0,0,0,9},
		{1,0,1,0,1,0,1,1,1,0,0,0,0,9},
		{1,0,1,1,1,0,1,1,1,0,0,0,0,9},
		{1,1,1,0,1,0,1,0,1,1,1,0,0,0,0,9},
		{1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,9},
		{1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,9},	/* Z */
		{1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9},	/* 0 */
		{1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9},		/* 1 */
		{1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9},		/* 2 */
		{1,0,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,9},			/* 3 */
		{1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,9},			/* 4 */
		{1,0,1,0,1,0,1,0,1,0,0,0,0,9},				/* 5 */
		{1,1,1,0,1,0,1,0,1,0,1,0,0,0,0,9},			/* 6 */
		{1,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,0,9},			/* 7 */
		{1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,9},		/* 8 */
		{1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,0,0,9},		/* 9 */
		{0,0,0,0,9},					    /* space */
		{1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,9},	      /* . */
		{1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,9},    /* , */
		{1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,9},	      /* ? */
		{1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,0,9},        /* : */
		{1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,9},	      /* ; */
		{1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,9},    /* ( */
		{1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,0,9},		      /* / */
		{1,1,1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,9},		      /* - */
		{1,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,9},		    /* ) AR */
		{1,0,1,1,1,0,1,0,1,0,1,0,0,0,0,9},		    /* ! AS */
		{1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,9},		    /* = DE */
		{1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,9},	    /* | SK */
		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9},	  /* % pause */
		{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9},	  /* * tone */
	};


/*
 * Open the hex file.
 */
	if((Hexfile = fopen(HEXFILENAME, "w")) == NULL)
	{
		printf("as: can't open %s\n", HEXFILENAME);
		exit(1);
	}

	cp=instr;

	printf ("\nWB0RIO CW to Intel Hex EPROM encoder program Version 1.1\n");
	printf ("\ncw2hex comes with ABSOLUTELY NO WARRANTY");
	printf ("\nThis is free software, and you are welcome to");
	printf ("\nredistribute it under the restrictions of the");
	printf ("\nGNU copyright, see the file COPYING for details\n");
	printf ("\nValid Chars: A-Z 0-9 .,?:;() and below:\n");
	printf ("\nEnter		SEND");
	printf ("\n-----		----");
	printf ("\n#		AR");
	printf ("\n!		AS");
	printf ("\n=		DE");
	printf ("\n/		DN");
	printf ("\n|		SK");
	printf ("\n-		Break");
	printf ("\n%%		Pause");
	printf ("\n*		Tone");
	printf ("\n");

/*
 * Get the string to encode here.
 */
	printf ("\nType a message to encode: ");
	fgets (instr, sizeof(instr)-1, stdin);

/*
 * Loop through all of the characters of the encode string.
 */
	while (*cp)
	{
		uc=toupper (*cp++);

/*
 * Convert letters top upper case and generate an index into the
 * morse array for letters and numbers.  The switch statement
 * sorts out the rest of the oddball characters.
 */
		if (uc >= 'A' && uc <= 'Z')
			i=(int)(uc - 'A');
		else if (uc >= '0' && uc <= '9')
			i=(int)(uc - '0' + 26);
		else
		{
			switch (uc)
			{
			case ' ':
				i=36;
			break;
			case '.':
				i=37;
			break;
			case ',':
				i=38;
			break;
			case '?':
				i=39;
			break;
			case ':':
				i=40;
			break;
			case ';':
				i=41;
			break;
			case '(':
			case ')':
				i=42;
			break;
			case '/':
				i=43;
			break;
			case '-':
				i=44;
			break;
			case '#':
				i=45;
			break;
			case '!':
				i=46;
			break;
			case '=':
				i=47;
			break;
			case '|':
				i=48;
			break;
			case '%':
				i=49;
			break;
			case '*':
				i=50;
			break;
			default:
				i=39;
			break;
			}
		}

		printf ("\n(%c) ", uc);

		j=0;

/*
 * Output each byte in a given morse character.
 */
		while (morse[i][j] != 9)
			outbyte ((int)morse[i][j++],0);
	}

	printf ("\n(EOM) ");

/*
 * Get the final length of the file then close up shop.
 */
	len=outbyte (2,0);	/* eom */
	outbyte (0,1);  /* close out hex file */

	fclose (Hexfile);

	printf ("\n\nThis message is %d bytes long.", len);
	printf ("\nThe Hex file is called %s\n\n", HEXFILENAME);

	return (-1);
}

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

/*
 * Output bytes to an Intel Hex format file.
 */

#define LINEBYTES 16

int outbyte (int byte, int finish)
{
	static int bcount=LINEBYTES;
	static int chksum=LINEBYTES;
	static int addr=0;
	static int sumout=0;
	int i;

	if (finish)
	{
/*
 * Fill out the last bytes as 0.
 */
		for (i=1; i<LINEBYTES-bcount; i++)
			hexbout (0);

		if (!sumout)
			hexbout (chksum);
		fprintf (Hexfile, "\n");
		return (0);
	}

	printf ("%d", byte);

/*
 * Deal with the end of line stuff here.
 */
	if (bcount >= LINEBYTES-1)
	{
		bcount=0;
		fprintf (Hexfile, "\n:");
		hexbout (LINEBYTES);
		hexwout (addr);

		chksum += addr>>8;
		chksum += addr&255;
		chksum += byte;
		sumout=0;

		fprintf (Hexfile, "00");

		hexbout (byte);

		chksum=LINEBYTES;
	}
	else
	{
		bcount++;

		hexbout (byte);

		chksum += byte;
		sumout=0;

		if (bcount == LINEBYTES-1)
		{
			hexbout (chksum);
			sumout=1;
		}
	}

	addr++;

	return (addr);
}

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

void hexbout(byte)	/* output a byte in hex */
int     byte;
{
	char    *hexstr = { "0123456789ABCDEF" } ;

	byte = byte & 0377;
	fprintf (Hexfile,"%c%c",hexstr[byte>>4],hexstr[byte&017]);
}

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

void hexwout(word)	/* output a word in hex */
int     word;
{
        hexbout(word>>8);	/* high byte of word */
	hexbout(word&255);	/* low byte of word */
}

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