#include "SendMorse.h"

#define		MORSE_C1000		3579
#define		MORSE_PERIOD	500
#define		MORSE_LENGTH	6
#define		MORSE_SPACE		6			/* # of dits between words */

BYTE sinewave[8] = {0, 90, 127, 90, 0, -90, -127, -90};

struct Device	*auDevice=0;
struct IOAudio	*audioIOB;
struct IOAudio	*aulockIOB;
struct IOAudio	*aufreeIOB;
BYTE			*chipaudio = 0;

struct MsgPort *auReplyPort, *auLockPort;

extern UBYTE			*AllocMem();
extern struct MsgPort	*CreatePort();

struct IOAudio			*CreateAudioIO();
UBYTE					GetAnyChannel();
void					FreeAudioIO();

#define isalpha(c)	(((c>='a') && (c<='z')) || ((c>='A') && (c<='Z')))
#define isdigit(c)	((c >= '0') && (c <= '9'))

long	sendrate = 5, ditcycles, dahcycles, ditlength;

main(argc,argv)
int argc;
char **argv;
{
	short i;

	GetSoundStuff();
	for (i = 1; i < argc; i++)
	{
		if (*argv[i] == '-')
		{
			sendrate = atoi(argv[i]+1);
			if (sendrate <= 0)
				finishup("usage: code [-sendrate] <filelist>");
		}
		else
			Work(argv[i]);
	}

	FreeAChannel(aufreeIOB);
	finishup("all done");
}


GetSoundStuff()
{
	int		i;
	UBYTE	chan;

	audioIOB  = CreateAudioIO();
	aulockIOB = CreateAudioIO();
	aufreeIOB = CreateAudioIO();

	if(audioIOB == 0 || aufreeIOB == 0 | aulockIOB == 0)
		finishup("out of memory!");

	if ((chipaudio = (BYTE *)AllocMem(8L, MEMF_CHIP)) == 0)
		finishup("out of memory!");
	for (i = 0; i < 8; i++)
		chipaudio[i] = sinewave[i];

	if (OpenDevice("audio.device",0L,audioIOB,0L))
		finishup ("audio device won't open!");

/* Get the device address for later use */
	auDevice = audioIOB->ioa_Request.io_Device;

/* Create ports for replies from the device */
	auReplyPort = CreatePort(0L,0L);
	auLockPort  = CreatePort(0L,0L);

	if(auReplyPort == 0 || auLockPort == 0) 
		finishup("cannot create a port!");

/*
 * initialize port addresses and device fields 
 * for all audio request blocks 
 */
	audioIOB->ioa_Request.io_Device = auDevice;
	aulockIOB->ioa_Request.io_Device = auDevice;

	audioIOB->ioa_Request.io_Message.mn_ReplyPort  = auReplyPort;
	aulockIOB->ioa_Request.io_Message.mn_ReplyPort  = auLockPort;

	chan = GetAnyChannel(audioIOB);

	/* Make the allocation keys match */
	aulockIOB->ioa_AllocKey = audioIOB->ioa_AllocKey;

	/* Make the unit numbers match */
	aulockIOB->ioa_Request.io_Unit = audioIOB->ioa_Request.io_Unit;

	LockAChannel(aulockIOB,chan);

/*
 * If checkio returns true, it means the request has
 * been returned.  This means the channel has been
 * stolen.
 */

	if(CheckIO(aulockIOB))
		finishup("A channel was stolen!");

/*
 * now assuming nothing stolen, setup and request
 * an output from that channel.
 */
	audioIOB->ioa_Data   = (UBYTE *)chipaudio;
	audioIOB->ioa_Length = 8/2; 		/* 4 WORDS in table */
	audioIOB->ioa_Period = MORSE_PERIOD;	/* from table */
	audioIOB->ioa_Volume = 64;			/* maximum */
	audioIOB->ioa_Cycles = 1000;		/* # of times */

	audioIOB->ioa_Request.io_Command = CMD_WRITE;
	audioIOB->ioa_Request.io_Flags = ADIOF_PERVOL;

	/* copy the audio block for freeing channels later */
	*aufreeIOB = *audioIOB;

}


finishup(string)
char *string;
{
	if(auDevice) CloseDevice(audioIOB);
	if(chipaudio) FreeMem(chipaudio,8L);
	if(audioIOB) FreeAudioIO(audioIOB);
	if(aulockIOB) FreeAudioIO(aulockIOB);
	if(auReplyPort) DeletePort(auReplyPort);
	if(auLockPort)  DeletePort(auLockPort);

	printf("%ls\n",string);
	exit(0);
}



/* newaudioblock.c */

struct IOAudio *
CreateAudioIO()
{
	struct IOAudio *iob;

	iob = (struct IOAudio *) AllocMem((long)sizeof(struct IOAudio),
			MEMF_CHIP | MEMF_CLEAR);

	return(iob);	/* returns 0 if out of memory */
}

void	
FreeAudioIO(iob)
struct IOAudio *iob;
{
	FreeMem(iob, (long)sizeof(struct IOAudio));
}



/* lockachannel.c */

LockAChannel(lockiob,channel)
struct IOAudio *lockiob;
UBYTE channel;
{
	/* tell it which channel to lock */

/*	lockiob->ioa_Request.io_Unit = (struct Unit *)channel;	*/

	lockiob->ioa_Request.io_Command = ADCMD_LOCK;
	lockiob->ioa_Request.io_Flags = 0;

	/* Send this command.  It does not return to 
	 * the reply port unless and until either this
	 * task frees the channel or another channel of
	 * higher precedence steals it.  Appropriate
	 * to keep two reply ports, perhaps... one for
	 * standard I/O replies, other for channel steal
	 * requests. 
	 */
	BeginIO(lockiob);
}

FreeAChannel(iob)
struct IOAudio *iob;
{
	/* allocation key and unit number must already be valid */
	iob->ioa_Request.io_Command = ADCMD_FREE;
	iob->ioa_Request.io_Flags = IOF_QUICK;
	BeginIO(iob);
	WaitIO(iob);
}

/* getaudio.c */


UBYTE
GetAnyChannel(iob)
struct IOAudio *iob;
{
	UBYTE anychan[4];
	UBYTE mychan;
	int error;

	anychan[0] = 1;
	anychan[1] = 2;
	anychan[2] = 4;
	anychan[3] = 8;

	iob->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
	iob->ioa_Request.io_Command = ADCMD_ALLOCATE;
	iob->ioa_Data = (UBYTE *)anychan;
	iob->ioa_Length = 4;
	iob->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
	BeginIO(iob); 
	error = WaitIO(iob);  /* returns nonzero if error */

	if(!(iob->ioa_Request.io_Flags & IOF_QUICK))
		GetMsg(iob->ioa_Request.io_Message.mn_ReplyPort);
	if(error)
		return(0);
	mychan = ((ULONG)(iob->ioa_Request.io_Unit)) & 0xFF;
	return(mychan);
}




#define		MAX_LETTERS		47
char *letters[MAX_LETTERS] =
{
	".-",				/* 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 */
	"-----",				/* 0 */
	".----",				/* 1 */
	"..---",				/* 2 */
	"...--",				/* 3 */
	"....-",				/* 4 */
	".....",				/* 5 */
	"-....",				/* 6 */
	"--...",				/* 7 */
	"---..",				/* 8 */
	"----.",				/* 9 */
	"--..--",				/* , */
	".-.-.-",				/* . */
	"..--..",				/* ? */
	"-.-.-.",				/* ; */
	"---...",				/* : */
	"-..-.",				/* / */
	"-....-",				/* - */
	".----.",				/* ' */
	"-.--.-",				/* () */
	"..--.-",				/* _ */
};



Work(fname)
char *fname;
/*
 * Get strings and send them to the audio port.
 *
 * Dlen: 1000 millis/sec * 1/8 chars/dit * 1/25 min/chars * 1/60 secs/min
 */
{
	char	*cptr, line[132];
	FILE	*file;

	if ((file = fopen(fname, "r")) == NULL)
		finishup("can't open a file");
	ditlength = 75 / sendrate;		/* In 20 milliseconds */
 	ditcycles = 12 * (MORSE_C1000 / MORSE_PERIOD);
	dahcycles = ditcycles * 3;
	while (fgets(line, 132, file))
	{
		for (cptr = line; *cptr && (*cptr != '\n'); cptr++)
		{
			SendLetter(*cptr);
			PauseDit(3);
		}
	}
	fclose(file);
}


SendLetter(c)
char c;
/*
 * Send character c.
 */
{
	char	*cptr, *temp = ",.?;:;/-,{}_", *findchar();
	short	i;

	if (c == ' ')
	{
		PauseDit(MORSE_SPACE);
		return;
	}
	if (isalpha(c))
		c = tolower(c) - 'a';
	else if (isdigit(c))
		c = c - 'a' + 26;
	else
	{
		cptr = findchar(temp, c);
		c = 37 + cptr - temp;
	}
	cptr = letters[c];
	i = 0;
	for ( ; *cptr != 0; cptr++, i++)
	{
		if (i)
			PauseDit(1);
		/*
		 * We'll send each dit or dah.  We know it's done when WaitIO
		 *		returns.  I think.
		 */
		if (*cptr == '.')
			audioIOB->ioa_Cycles = ditcycles;
		else
			audioIOB->ioa_Cycles = dahcycles;
		BeginIO(audioIOB);
		WaitIO(audioIOB);
	}
}

char *findchar(s,c)
char *s,c;
{
	for ( ; *s; s++)
		if (*s == c)
			return(s);
	return(NULL);
}


PauseDit(ditcount)
short ditcount;
/*
 * Pause for ditcount dit periods.
 *
 *		Do this by setting the timer and waiting for it.
 */
{
	Delay((long)(ditcount * ditlength));
}
