#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));
}
