/*********************************************************************
 * PROGRAM NAME:  AROEN.C
 *--------------------------------------------------------------------
 *      This program provides an all mode amateur radio operating
 *  environment.  It is designed to work spegetchfically with an AEA
 *  PK232 'PAKRATT' node controller and the Kenwood TS440S tranceiver.
 *  Complete control of both the PK232 and the 440S is available from
 *  the PC keyboard.
 *--------------------------------------------------------------------
 *  MODIFICATIONS:
 *      04/18/87    Original Source
 *      03/23/88    Ported to Turbo C
 ********************************************************************/

#include <stdio.h>
#include <dos.h>
#include <litecomm.h>
#include <time.h>
#include <conio.h>
#include "aroen.h"

#define VIDEO 0x10

FILE *log_file;
FILE *init_file;
FILE *send_file;
FILE *save_file;
FILE *printer;

/* TS440 Information string received on IF or AI1 CMD */
struct ts440_if {
    char if_type[2];
    char p0[3];         /* P00  */
    char freq[8];       /* P01  */
    char p2[5];         /* P02  */
    char rit_freq[5];   /* P03  */
    char rit_on;        /* P04  */
    char xit_on;        /* P05  */
    char p6;            /* P06  */
    char mem_chan[2];   /* P07  */
    char tx_rx_flag;    /* P08  */
    char mode;          /* P09  */
    char function;      /* P10  */
    char scan_on;       /* P11  */
    char split_on;      /* P12  */
    char p13[6];        /* P13  */
    };

int ts440_mode;
char *ts440_mode_str[] = {"   ","LSB", "USB", "CW ", "FM ", "AM ", "FSK"};

int pk232_mode;
char *pk232_mode_str[] = {"ARQ", "VOICE", "VOICE", "MORSE", "VOICE",
                          "VOICE", "ASCII", "BAUDOT", "AMTOR", "PACKET",
                          "ALIST", "FEC", };
char *tx_mode[] = {"RCVE", "XMIT"};

char cq_str[80];
char qrz_str[80];
char ga_str[] = "K K PSE";
char ry_str[] = "RYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYR";
char my_call[15];
char my_name[20];
char my_qth[25];
char my_equip[80];
char save_fn[80];
char my_log[80];

int tx_flag = FALSE;
int tx_col = 0;
int save = FALSE;
int print = FALSE;

char ts_440_freq[10];

int ts440_port = 2;
int pk232_port = 1;

struct ts440_if ts440_info;
char *ts440_buf;

int index_440 = 0;

char his_selcal[5];

int  year, month, day, hour, sec;
int min = 99;
char date[] = "27 JUN 87";
char time_of_day[] = "00:00Z";
char *mon_name[] = {" ", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
                            "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
struct {
    char frequency[10];
    char mode[6];
    char power[5];
    char date[10];
    char start[7];
    char stop[7];
    char call_sign[16];
    char rst_sent[4];
    char rst_rcvd[4];
    char name[21];
    char qth[31];
    char comments[56];
    char contest[21];
    char qsl_send[2];
    char qsl_rcvd[2];
    } qso;

struct {
    int frow;
    int fcol;
    int tcol;
    int trow;
    char buf[512];
    } cur_window;
int ch_k, ch_pk, ch_440;
int gmt_offset = 6;
int v_attribute = YELLOW;

void main()
{
    int cmd;

    init_sys();
    do {
        get_time(0);
        if (kbhit()) {
            ch_k = getch();
            if (ch_k == 0) {
                ch_k = getch() + 128;
                cmd = exec_cmd(ch_k);
                if (cmd == EXIT) {
                    if (qso.call_sign[0] != 0)
                        log_call();
                    comm_close(1);
                    comm_close(2);
                    if (save)
                        close(save_file);
                    if (print) close(printer);
                    exit(0);
                    }
                }
            else if (tx_flag) {
                lc_put(pk232_port, ch_k);
                if (ch_k == 4)
                    co_tx_str("<CTL-D>");
                if (ch_k > 31)
                    if (++tx_col > 60)
                        chr_out(BELL);
                if (tx_col > 68) {
                    lc_put(pk232_port, CR);
                    co_tx(CR);
                    tx_col = 0;
                    }
                co_tx(ch_k);
                if (ch_k == CR)
                    tx_col = 0;
                }
            }
        if (lc_icnt(pk232_port) > 0)
            co_rx((ch_pk = lc_get(pk232_port)) & 0x7f);
        if (lc_icnt(ts440_port) > 0) {
            ts440_buf[index_440++] =
                (ch_440 = lc_get(ts440_port));
            if (ch_440 == ';') {
                disp_440_info();
                index_440 = 0;
                }
            if (index_440 > 38)
                index_440 = 0;
            }
        }
    while (FOREVER);
    }   /*  END MAIN */

/*******************************************************************
 * SUBROUTINE NAME:  init_sys
 *------------------------------------------------------------------
 *      This routine initializes the system by performing the
 *  following tasks;
 *      o   Clear Screen, set up split screen for xmit and rceive.
 *      o   Initialize printer
 *      o   Initialize ASYNC1 and ASYNC2 serial I/O drivers
 *      o   Open Log file
 *      o   Open initialization files
 *      o   Initialize system tables
 *      o   Initialize PK-232
 *      o   Initialize status line
 ******************************************************************/

 init_sys()
 {
    static char ts440_init[] = ";AI1;";
    int i;
    char tempstr[20], ch, *err;

    ts440_buf = &ts440_info;
    init_file = fopen("AROEN.MSG", "r");
    if (init_file == 0) {
        co_str("UNABLE TO OPEN 'AROEN.MSG'\n");
        co_str("Use your favorite text editor to create it as follows:\n");
        co_str("    PK232 COMM PORT\n");
        co_str("    TS440 COMM PORT\n");
        co_str("    Call Sign\n");
        co_str("    Name\n");
        co_str("    QTH\n");
        co_str("    Log file path and file name\n");
        co_str("    CQ Message\n");
        co_str("    QRZ Message\n");
        co_str("    Equipment file path and file name\n");
        co_str("    Save file path and file name\n");
        exit(1);
        }
    else {
        err = fgets(tempstr, 20, init_file);
        if (err == NULL) {
            printf("Error reading AROEN.MSG\n");
            exit(1);
            }
        for (i = 0; i < 20; i++)
            if ((tempstr[i] >= '1') && (tempstr[i] <= '4'))
                break;
        if (i < 20)
           pk232_port = tempstr[i] - '0';
        err = fgets(tempstr, 20, init_file);
        if (err == NULL) {
            printf("Error reading AROEN.MSG\n");
            exit(1);
            }
        for (i = 0; i < 20; i++)
            if ((tempstr[i] >= '1') && (tempstr[i] <= '4'))
                break;
        if (i < 20)
           ts440_port = tempstr[i] - '0';
        if (ts440_port == pk232_port) {
            printf("ERROR in PORT ASSIGNMENTS...Aborting\n");
            exit(1);
            }

        init_str(my_call, 15);
        init_str(my_name, 15);
        init_str(my_qth, 25);
        init_str(my_log, 80);
        init_str(cq_str, 80);
        init_str(qrz_str, 80);
        init_str(my_equip, 80);
        init_str(save_fn, 80);
        }
    close(init_file);
    printer = fopen("PRN:", "w");
    if (comm_opn(pk232_port, B1200, NPARITY, BIT8, STOP1, 4096, 256) == -1)
    {
        co_str("Error Opening COM1 (PK232).\n");
        exit(1);
    }
    lc_setmdm(pk232_port, DTR | RTS);
    if (comm_opn(ts440_port, B4800, NPARITY, BIT8, STOP1, 128, 128) == -1)
    {
        co_str("Error Opening COM2 (TS440).\n");
        exit(1);
    }
    lc_setmdm(ts440_port, DTR | RTS);
    send_str(TS440, ts440_init);
    init_screen();
    get_time(1);
    get_time(0);
    send_cmd(PK232, "\003ECHO OFF\015");
    send_cmd(PK232, "USOS ON\015");  /* unshift on space */
    send_cmd(PK232, "EAS ON\015");   /* echo as sent */
    sprintf(tempstr, "DAYTIME %02d%02d%02d%02d%02d\015",
                        year, month, day, hour, min);
    build_window(5,11,7,61);
    gotoxy(14, 6);
    co_str("Press any key to initialize PK232");
    getch();
    rstr_scr();
    send_cmd(PK232, tempstr);
    send_cmd(PK232, "AMTOR\015");
    send_cmd(PK232, "BAUDOT\015");
    pk232_mode = BAUDOT;
    gotoxy(33, 2);
    co_str(pk232_mode_str[pk232_mode]);
    send_str(TS440, "MD6;");
    }

int init_str(char *str, int len)
{
    char *err;

    err = fgets(str, len, init_file);
    if (err == NULL) {
        printf("Error reading AROEN.MSG\n");
        exit(1);
        }
    str[strlen(str) - 1] = 0;
    }


init_screen()
{
    int i, j;

    clrscr();
    for (j = 1; j <= 24; j++)
        for (i = 1; i <= 80; i++)
           chr_out(32);
    v_attribute = GREEN;  /* dark green on black */
    gotoxy(1,1);
    chr_out(ULC);
    for (i = 2; i < 80; i++) {
        gotoxy(i, 1);
        chr_out(HB);
        }
    gotoxy(i, 1);
    chr_out(URC);
    gotoxy(2, 3);
    for (i = 2; i < 80; i++) {
        gotoxy(i, 3);
        chr_out(HB);
        }
    for (i = 2; i < 80; i++) {
        gotoxy(i, 19);
        chr_out(HB);
        }
    gotoxy(1, 25);
    chr_out(LLC);
    for (i = 2; i < 80; i++) {
        gotoxy(i, 25);
        chr_out(HB);
        }
    gotoxy(i, 25);
    chr_out(LRC);
    for (i = 2; i < 25; i++) {
        gotoxy(1, i);
        chr_out(VB);
        gotoxy(80, i);
        chr_out(VB);
        }
    prnt_t(20);
    prnt_t(30);
    prnt_t(46);
    prnt_t(39);
    prnt_t(54);
    prnt_t(62);
    prnt_t(72);
    gotoxy(1, 3);
    chr_out(LRA);
    gotoxy(80, 3);
    chr_out(RRA);
    gotoxy(1, 19);
    chr_out(LRA);
    gotoxy(80, 19);
    chr_out(RRA);
    v_attribute = MAGENTA;
    gotoxy(6, 1);
    co_str("FREQ");
    gotoxy(25, 1);
    co_str("QSO");
    gotoxy(34, 1);
    co_str("MODE");
    gotoxy(42, 1);
    co_str("SAVE");
    gotoxy(50, 1);
    co_str("PTT");
    gotoxy(57, 1);
    co_str("PRINT");
    gotoxy(66, 1);
    co_str("DATE");
    gotoxy(75, 1);
    co_str("TIME");
    gotoxy(37, 3);
    co_str("TEXT IN");
    gotoxy(37, 19);
    co_str("TEXT OUT");
    gotoxy(34, 25);
    co_str("AROEN by K5WNV");
    v_attribute = YELLOW;
    gotoxy(42, 2);
    co_str("OFF");
    gotoxy(58, 2);
    co_str("OFF");
    }

prnt_t(col)   /* print vertical bar with T at top and bottom */
int col;
{
    col++;
    gotoxy(col, 1);
    chr_out(DN_T);
    gotoxy(col, 2);
    chr_out(VB);
    gotoxy(col, 3);
    chr_out(UP_T);
    }

chr_out(ch)
int ch;
{
    union REGS regs;

    regs.h.ah = 9;
    regs.h.al = ch;
    regs.h.bl = v_attribute;
    regs.h.bh = 0;
    regs.x.cx = 1;
    int86(VIDEO, &regs, &regs);
    }

disp_440_info()
{
    int i;
    char buf[20];
    if (strncmp(ts440_info.if_type, "IF", 2))
        return(0);
    for (i = 0; i < 5; i++)
        ts_440_freq[i] = ts440_info.freq[i];
    if (ts_440_freq[0] == '0')
        ts_440_freq[0] = ' ';
    ts_440_freq[i++] = '.';
    for (;i < 9; i++)
        ts_440_freq[i] = ts440_info.freq[i-1];
    ts_440_freq[9] = 0;
    gotoxy(3, 2);
    ts440_mode = ts440_info.mode - 0x30;
    sprintf(buf, "%s KHZ/%3s", ts_440_freq, ts440_mode_str[ts440_mode]);
    co_str(buf);
    i = ts440_info.tx_rx_flag - 0x30;
    if ((i == 0) || (i == 1)) {
        gotoxy(49, 2);
        co_str(tx_mode[i]);
        }
    }

int exec_cmd(ch)
int ch;
{
    static char up440_str[] ="UP;";
    static char dn440_str[] ="DN;";
    int i, j;

    switch (ch) {
        case DN  : send_str(TS440, dn440_str);
                   break;
        case PGDN : for (i = 0; i < 100; i++)
                        send_str(TS440, dn440_str);
                    break;
        case UP  : send_str(TS440, up440_str);
                   break;
        case PGUP : for (i = 0; i < 100; i++)
                        send_str(TS440, up440_str);
                    break;
        case F1  : help();
                   break;
        case F2  : chg_mode();
                   break;
        case F3  : call_cq();
                   break;
        case F4  : call_qrz();
                   break;
        case F5  : log_call();
                   break;
        case F6  : call();
                   break;
        case F7  : chg_freq();
                   break;
        case F8  : rcve();
                   break;
        case F9  : cmd();
                   break;
        case F10 : xmit();
                   break;
        case CTL_F2  :  lc_gotxoff(pk232_port);
                        lc_gotxoff(ts440_port);
                        break;
        case ALT_F2  :  build_window(4,10, 8, 70);
                        gotoxy(12, 5);
                        send_data();
                        rstr_scr();
                        break;
        case ALT_F4  :  xmit_eqp();
                        break;
        case ALT_F6  :  save = !save;
                        gotoxy(42, 2);
                        if (save) {
                            save_file = fopen(save_fn, "a");
                            co_str("ON ");
                            }
                        else {
                            close(save_file);
                            co_str("OFF");
                            }
                        break;
        case ALT_F8  :  print = !print;
                        gotoxy(58, 2);
                        if (print)
                            co_str("ON ");
                        else
                            co_str("OFF");
                        break;
        case ALT_F10 : clrscr();
                      return(EXIT);
        case SHF_F1  : send_cmd(PK232, "\003TC\015");
                       break;
        case SHF_F2  : send_cmd(PK232, "\003L\015");
                       break;
        case SHF_F3  : send_cmd(PK232, "\003RXREV ON\015");
                       break;
        case SHF_F4  : send_cmd(PK232, "\003RXREV OFF\015");
                       break;
        case SHF_F5  : send_cmd(PK232, "\003RBAUD 75\015");
                       break;
        case SHF_F6  : send_cmd(PK232, "\003RBAUD 45\015");
                       break;
        case SHF_F8  : send_cmd(PK232, "\003R\015");
                       tx_flag = FALSE;
                       break;
        case SHF_F10 : send_cmd(PK232, "\003X\015");
                       tx_flag = TRUE;
                       break;
        default  : break;
        }
    return(0);
    }

help()
{
    int ch;

    ch = '1';
    build_window(5,5, 16, 39);
    while ((ch >= '1') && (ch <= '4'))
        switch (ch) {
            case '1' : ch = disp_help0();
                       break;
            case '2' : ch = disp_help1();
                       break;
            case '3' : ch = disp_help2();
                       break;
            case '4' : ch = disp_help3();
                       break;
            }
    rstr_scr();

    }

disp_help0()
{
    int ch;

    /* clear window */
    scr_scrup(0,cur_window.frow, cur_window.fcol,
                cur_window.trow-2, cur_window.tcol-2);
    gotoxy(13, 6);
    co_str("     HELP FK");
    gotoxy(13, 7);
    co_str("HELP -F1  F2- MODE");
    gotoxy(13, 8);
    co_str("  CQ -F3  F4- QRZ ");
    gotoxy(13, 9);
    co_str(" LOG -F5  F6- CALL");
    gotoxy(13, 10);
    co_str("FREQ -F7  F8- RCVE");
    gotoxy(13, 11);
    co_str(" CMD -F9 F10- XMIT");
    gotoxy(13, 13);
    co_str(" Press Any Fn Key");
    gotoxy(13, 14);
    co_str(" for Help, ESC to");
    gotoxy(13, 15);
    co_str("     to Exit");
    ch = getch();
    return(ch);
    }

disp_help1()
{
    int ch;

    /* clear window */
    scr_scrup(0,cur_window.frow, cur_window.fcol,
                cur_window.trow-2, cur_window.tcol-2);
    gotoxy(13, 6);
    co_str("  HELP CTL_FK");
    gotoxy(13, 7);
    co_str("     -F1  F2-CLEAR XOFF");
    gotoxy(13, 8);
    co_str("     -F3  F4-     ");
    gotoxy(13, 9);
    co_str("     -F5  F6-     ");
    gotoxy(13, 10);
    co_str("     -F7  F8-     ");
    gotoxy(13, 11);
    co_str("     -F9 F10-     ");
    gotoxy(13, 13);
    co_str(" Press Any Fn Key");
    gotoxy(13, 14);
    co_str(" for Help, ESC to");
    gotoxy(13, 15);
    co_str("     to Exit");
    ch = getch();
    return(ch);
    }

disp_help2()
{
    int ch;

    /* clear window */
    scr_scrup(0,cur_window.frow, cur_window.fcol,
                cur_window.trow-2, cur_window.tcol-2);
    gotoxy(13, 6);
    co_str("      HELP SHIFT_FK");
    gotoxy(13, 7);
    co_str("  CLEAR -F1  F2- LETTERS");
    gotoxy(13, 8);
    co_str(" NORMAL -F3  F4- REVERSE");
    gotoxy(13, 9);
    co_str("BAUD 75 -F5  F6- BAUD 45");
    gotoxy(13, 10);
    co_str("        -F7  F8- RCVE");
    gotoxy(13, 11);
    co_str("        -F9 F10- XMIT");
    gotoxy(13, 12);
    co_str(" Press Any Fn Key");
    gotoxy(13, 14);
    co_str(" for Help, ESC to");
    gotoxy(13, 15);
    co_str("     to Exit");
    ch = getch();
    return(ch);
    }

disp_help3()
{
    int ch;

    /* clear window */
    scr_scrup(0,cur_window.frow, cur_window.fcol,
                cur_window.trow-2, cur_window.tcol-2);
    gotoxy(13, 6);
    co_str("   HELP ALT_FK");
    gotoxy(13, 7);
    co_str("     -F1  F2- DATA");
    gotoxy(13, 8);
    co_str("     -F3  F4- EQUIP");
    gotoxy(13, 9);
    co_str("     -F5  F6- SAVE");
    gotoxy(13, 10);
    co_str("     -F7  F8- PRINT");
    gotoxy(13, 11);
    co_str("     -F9 F10- EXIT");
    gotoxy(13, 13);
    co_str(" Press Any Fn Key");
    gotoxy(13, 14);
    co_str(" for Help, ESC to");
    gotoxy(13, 15);
    co_str("     to Exit");
    ch = getch();
    return(ch);
    }

chg_mode()
{
    int ch, i;

    build_window(5,11, 15, 36);
    gotoxy(14, 7);
    co_str("0. ARQ       1. LSB");
    gotoxy(14, 8);
    co_str("2. USB       3. MORSE");
    gotoxy(14, 9);
    co_str("4. FM        5. AM");
    gotoxy(14, 10);
    co_str("6. ASCII     7. BAUDOT");
    gotoxy(14, 11);
    co_str("8. AMTOR     9. PACKET");
    gotoxy(14, 13);
    co_str("SELECT: ");
    while (((ch = getch() - 0x30) < 0) || (ch > 9)) {
        if ((ch + 0x30) == ESC)
            break;
        else
            chr_out(BELL);
        }
    if (ch != ESC) {
        send_cmd(PK232, "\003TC\015");
        pk232_mode = ch;
        if ((pk232_mode == ALIST) ||
            (pk232_mode == ARQ)) {
            send_cmd(PK232, "\003AMTOR\015");
            tx_flag = FALSE;
            }
        switch(ch) {
            case 0 : send_str(TS440, "MD6;");
                     send_cmd(PK232, "\003AMTOR\015");
                     rstr_scr();
                     build_window(5,11, 8, 36);
                     gotoxy(15, 6);
                     co_str("Xmit Mode? (Y/N): ");
                     ch = toupper(getch());
                     if (ch == 'Y') {
                        gotoxy(13, 7);
                        tx_flag = TRUE;
                        xmit_arq();
                        }
                     else {
                        send_cmd(PK232, "\003ALIST\015");
                        pk232_mode = ALIST;
                        }
                     break;
            case 1 : send_str(TS440, "MD1;");
                     break;
            case 2 : send_str(TS440, "MD2;");
                     break;
            case 3 : send_str(TS440, "MD3;");
                     send_cmd(PK232, "\003AMTOR\015");
                     send_cmd(PK232, "\003MORSE\015");
                     break;
            case 4 : send_str(TS440, "MD4;");
                     break;
            case 5 : send_str(TS440, "MD5;");
                     break;
            case 6 : send_str(TS440, "MD6;");
                     send_cmd(PK232, "\003AMTOR\015");
                     send_cmd(PK232, "\003ASCII\015");
                     break;
            case 7 : send_str(TS440, "MD6;");
                     send_cmd(PK232, "\003AMTOR\015");
                     send_cmd(PK232, "\003BAUDOT\015");
                     break;
            case 8 : send_str(TS440, "MD6;");
                     send_cmd(PK232, "\003AMTOR\015");
                     break;
            case 9 : send_str(TS440, "MD6;");
                     send_cmd(PK232, "\003AMTOR\015");
                     gotoxy(13,13);
                     co_str("HF/VHF? (H/V): ");
                     while (((ch = toupper(getch())) != 'V') &&
                             (ch != 'H'));
                     send_cmd(PK232, "PACKET\015");
                     if (ch == 'H') {
                        send_cmd(PK232, "HBAUD 300\015");
                        send_cmd(PK232, "VHF OFF\015");
                        }
                     else {
                        send_cmd(PK232, "HBAUD 1200\015");
                        send_cmd(PK232, "VHF ON\015");
                        }

                     break;
            default : break;
            }
        }
    rstr_scr();
    disp_mode();
    }
    
chg_freq()
{
    char cmd_str[20];
    char ch;
    int err;

    build_window(5,11, 8, 62);
    gotoxy(13, 6);
    co_str("VFO A or B, Memory (A,B,M): ");
    while (((ch = toupper(getch())) != 'A') && (ch != 'B')
            && (ch != 'M')) {
        if (ch == ESC) {
            rstr_scr();
            return(0);
            }
        }
    chr_out(ch);
    gotoxy(13, 7);
    if (ch == 'M') {
        co_str("Memory Channel: ");
        err = enter_mem_channel(cmd_str);
        if (!err) {
            send_str(TS440, cmd_str);
            send_str(TS440, "FN2;");
            }
        }
    else {
        err = enter_freq(cmd_str, ch);
        if (!err) {
            send_str(TS440, cmd_str);
            if (ch == 'A')
                send_str(TS440, "FN0;");
            else
                send_str(TS440, "FN1;");
            }
    }
    rstr_scr();
    }

    
rcve()
{
    if (tx_flag == FALSE)
        return(0);
    switch (pk232_mode) {
        case MORSE  :
        case LSB :
        case USB :
        case FM  :
        case AM  : send_str(TS440, "RX;");
                   break;
        case ARQ : send_cmd(PK232, "\003R\015");
                   pk232_mode = AMTOR;
                   disp_mode();
                   break;
        case ASCII  :
        case BAUDOT : send_stop();
                      break;
        case AMTOR  : send_stop();
                      pk232_mode = AMTOR;
                      disp_mode();
                      break;
        case PACKET : send_cmd(PK232, "\003D\015");
                      break;
        default : break;
        }
    tx_flag = FALSE;
    }

xmit()
{
    if (tx_flag == TRUE)    /* not allowed in xmit mode */
        return(0);
    tx_flag = TRUE;
    switch (pk232_mode) {
        case 1 :
        case 2 :
        case 4 :
        case 5 : send_str(TS440, "TX;");
                 break;
        case 3 :
        case 6 :
        case 7 : send_cmd(PK232, "\003X\015");
                 send_start();
                 break;
        case 10 : send_cmd(PK232, "\003AMTOR\015");
        case 8  :
        case 11 : send_cmd(PK232, "\003FEC\015");
                  pk232_mode = FEC;
                  disp_mode();
                  send_start();
                  break;
        case 9 : xmit_packet();
                 break;
        default : break;
        }
    }

cmd()
{
    int ch, index, i;
    char tempstr[81];

    build_window(5,11, 7, 72);
    gotoxy(13, 6);
    co_str("CMD:");
    tempstr[0] = 3;
    index = enter_str(tempstr, 80, 1);
    if (index != -1) {
        tempstr[index] = CR;
        if (index > 2)
        send_cmd(PK232, tempstr);
        }
    rstr_scr();
    }

co_rx(ch)
int ch;
{
    static row = 18;
    static col = 2;

    if (save)
        fputc(ch, save_file);
    if (print)
        fputc(ch, printer);
    if (ch < 32) {
        switch (ch) {
            case LF : scr_scrup(1,3,1,17,78);
                      col = 2;
                      break;
            case BS : if (col > 2) {
                         gotoxy(--col, row);
                         chr_out(' ');
                         }
                      break;
            case BELL  : chr_out(ch);
                      break;
            default : break;
            }
        }
    else {
        gotoxy(col++, row);
            chr_out(ch);
        if (col > 79) {
            col = 2;
            if (++row > 18) {
                scr_scrup(1,3,1,17,78);
                row = 18;
                }
            }
        }
    }

co_tx(ch)
int ch;
{
    static row = 24;
    static col = 2;

    v_attribute = CYAN;
    if (ch < 32) {
        switch (ch) {
            case CR : scr_scrup(1,19,1,23,78);
                      col = 2;
                      break;
            case BS  : if (col > 2) {
                         gotoxy(--col, row);
                         chr_out(' ');
                         }
                      break;
            case BELL  : chr_out(ch);
                      break;
            default : break;
            }
        }
    else {
        gotoxy(col++, row);
            chr_out(ch);
        if (col > 79) {
            col = 2;
            if (++row > 24) {
                scr_scrup(1,19,1,23,78);
                row = 24;
                }
            }
        }
    v_attribute = YELLOW;
    }

/* write a character string to the TEXT OUT window */
co_tx_str(str)
char *str;
{
    int i;

    i = 0;
    while (str[i])
        co_tx(str[i++]);
    }

/* write a character string to the TEXT IN window */
co_rx_str(str)
char *str;
{
    int i;

    i = 0;
    while (str[i])
        co_rx(str[i++]);
    }

build_window(frow, fcol, trow, tcol)
int frow, fcol, trow, tcol;
{
    int i, j, index;

    /* save window contents */
    index = 0;
    for (i = frow; i <= trow; i++)
        for (j = fcol; j <= tcol; j++) {
            gotoxy(j, i);
            cur_window.buf[index++] = scr_sinp();
            }
    cur_window.frow = frow;
    cur_window.trow = trow;
    cur_window.fcol = fcol;
    cur_window.tcol = tcol;

    /* clear window */
    scr_scrup(0,frow - 1, fcol - 1, trow - 1, tcol - 1);
    /* build border */
    v_attribute = GREEN;
    gotoxy(fcol, frow);
    chr_out(ULC);
    for (i = fcol+1; i <= tcol; i++) {
        gotoxy(i, frow);
        chr_out(HB);
        }
    chr_out(URC);
    gotoxy(fcol, trow);
    chr_out(LLC);
    for (i = fcol+1; i <= tcol; i++) {
        gotoxy(i, trow);
        chr_out(HB);
        }
    chr_out(LRC);
    for (i = frow+1; i < trow; i++) {
        gotoxy(fcol, i);
        chr_out(VB);
        gotoxy(tcol, i);
        chr_out(VB);
        }
    v_attribute = MAGENTA;
    }

rstr_scr()
{
    int i, j, index;

    index = 0;
    v_attribute = YELLOW;
    for (i = cur_window.frow; i <= cur_window.trow; i++)
        for (j = cur_window.fcol; j <= cur_window.tcol; j++) {
            gotoxy(j, i);
            chr_out(cur_window.buf[index++]);
            }
    }

get_time(int date_flag)
{
    struct tm *tm_now;
    long secs_now;
    char *str_now;

    time(&secs_now);
    tm_now = gmtime(&secs_now);
    if ((min == tm_now->tm_min) && (date_flag == 0))
            return(0);
    min = tm_now->tm_min;
    if (date_flag || (hour != tm_now->tm_hour)) {
        hour = tm_now->tm_hour;
        sprintf(date, "%2d %3s %02d", tm_now->tm_mday,
             mon_name[tm_now->tm_mon], tm_now->tm_year % 100);
        gotoxy(64, 2);
        co_str(date);
        }
    gotoxy(74, 2);
    sprintf(time_of_day, "%02d:%02dZ", hour, min);
    co_str(time_of_day);
    }

int enter_mem_channel(str)
char *str;
{
    int i, err;

    err = enter_str(str, 2, 0);
    if ((err == 0) || (err == -1))
        return(err);
    i = atoi(str);
    sprintf(str, "MC %02d;", i);
    return(0);
    }

int enter_str(str, len, offset)
char *str;
int len, offset;
{
    int i, x, y;
    char ch;

    for (i = offset; i < len; i++)
        str[i] = 0;
    i = getxy();
    y = 1 + (i >> 8);
    x = 1 + (i & 0xff);
    i = offset;
    do {
        ch = toupper(getch());
        if ((ch == CR) || (ch == ESC))
            break;
        if ((i > 0) && (ch == BS)) {
            gotoxy(--x, y);
            chr_out(' ');
            i--;
            }
        else if (ch > 31) {
            chr_out(ch);
            gotoxy(++x, y);
            str[i++] = ch;
            }
        }
    while (i < len);
    if (ch == ESC) {
        str[0] = 0;
        return(-1);
        }
    else
        return(i);
    }

int enter_freq(str, ch)
char *str;
char ch;
{
    char tempstr[80];
    int i, j, k, err;

    str[0] = 'F';
    str[1] = ch;
    for (i = 2; i < 13; i++)
        str[i] = '0';
    str[13] = ';';
    str[14] = 0;
    co_str("Frequency: ");
    err = enter_str(tempstr, 13, 0);
    if ((err == 0) || (err == -1))
        return(err);
    for (i = 0; i < err; i++)
        if (tempstr[i] == '.')
            break;
    if (i > 5)
        return(err);
    j = i;
    k = 9;
    while (i)
        str[k--] = tempstr[--i];
    k = 10;
    while (++j < err)
        str[k++] = tempstr[j];
    return(0);
    }

int xmit_arq()
{
    int i, err;

    co_str("SELCAL? ");
    err = enter_str(his_selcal, 4, 0);
    if (err == -1)
        return(err);
    send_cmd(PK232, "\003ARQ ");
    send_cmd(PK232, his_selcal);
    lc_put(pk232_port, CR);
    return(0);
    }

int xmit_packet()
{
    int i, err;
    char cmd_str[80];
    char ch;

    if (qso.call_sign[0] != 0) 
        log_call();
    build_window(5,11, 7, 76);
    gotoxy(13, 6);
    co_str("CALL SIGN? ");
    err = enter_str(qso.call_sign, 15, 0);
    if (err == -1)
        return(err);
    sprintf(cmd_str, "\003C %s\015", qso.call_sign);
    send_cmd(PK232, cmd_str);
    rstr_scr();
    }

disp_mode()
{
    int i;

    gotoxy(32, 2);
    co_str("        ");
    i = (7 - strlen(pk232_mode_str[pk232_mode]))/2;
    gotoxy(33 + i, 2);
    co_str(pk232_mode_str[pk232_mode]);
    }

call_cq()
{
    int i;

    /* Don't Call CQ if in TRANSMIT mode */
    if (tx_flag)
        return(0);
    xmit();
    co_tx(CR);
    lc_put(pk232_port, CR);
    for (i = 0; i < 3; i++) {
        send_str(PK232, cq_str);
        co_tx(CR);
        lc_put(pk232_port, CR);
        }
    send_str(PK232, ga_str);
    co_tx(CR);
    lc_put(pk232_port, CR);
    lc_put(pk232_port, 4);
    tx_flag = FALSE;
    }

call_qrz()
{
    int i;

    /* Don't QRZ if in TRANSMIT mode */
    if (tx_flag)
        return(0);
    xmit();
    co_tx(CR);
    lc_put(pk232_port, CR);
    send_str(PK232, ry_str);
    co_tx(CR);
    lc_put(pk232_port, CR);
    send_str(PK232, qrz_str);
    co_tx(CR);
    lc_put(pk232_port, CR);
    send_str(PK232, ga_str);
    co_tx(CR);
    lc_put(pk232_port, CR);
    lc_put(pk232_port, 4);
    tx_flag = FALSE;
    }

send_start()
{
    char tempstr[80];

    get_time(0);
    sprintf(tempstr, "\015%s - %s", date, time_of_day);
    send_str(PK232, tempstr);
    if (qso.call_sign[0] != 0)
        sprintf(tempstr, "\015 %s DE %s\015", qso.call_sign, my_call);
    else
        sprintf(tempstr, " %s\015", my_call);
    send_str(PK232, tempstr);
    }

send_stop()
{
    char tempstr[80];

    get_time(0);
    sprintf(tempstr, "\015%s - %s", date, time_of_day);
    send_str(PK232, tempstr);
    if (qso.call_sign[0] != 0) 
        sprintf(tempstr, "\015 %s DE %s\015K K K\015\004",
                        qso.call_sign, my_call);
    else 
        sprintf(tempstr, " DE %s\015K K K\015\004", my_call);
    send_str(PK232, tempstr);
    tx_flag = FALSE;
    }

call()
{
    char tempstr[80];

    /* Don't Call if in TRANSMIT mode */
    if ((tx_flag) || (pk232_mode > 8) || (pk232_mode == 0))
        return(0);
    if (pk232_mode != 8) 
        send_cmd(PK232, "\003X\015");
    else
        send_cmd(PK232, "\003FEC\015");
    co_tx(CR);
    lc_put(pk232_port, CR);
    send_str(PK232, ry_str);
    co_tx(CR);
    lc_put(pk232_port, CR);
    sprintf(tempstr, "%s %s %s DE %s %s +%s+ IN %s",
                qso.call_sign, qso.call_sign, qso.call_sign,
                    my_call, my_call, my_name, my_qth);
    send_str(PK232, tempstr);
    co_tx(CR);
    lc_put(pk232_port, CR);
    send_str(PK232, ga_str);
    lc_put(pk232_port, 4);
    tx_flag = FALSE;
    }


log_call()
{
    int i, ch, err;
    
    build_window(5,11, 7, 41);
    gotoxy(13, 6);
    if (qso.call_sign[0] == 0) {
        setmem(&qso, sizeof(qso), 0);
        strcpy(qso.date, date);
        strcpy(qso.start, time_of_day);
        strcpy(qso.frequency, ts_440_freq);
        if ((ts440_mode > 0) && (ts440_mode < 6))
            strcpy(qso.mode, ts440_mode_str[ts440_mode]);
        else
            strcpy(qso.mode, pk232_mode_str[pk232_mode]);
        co_str("CALL SIGN: ");
        err = enter_str(qso.call_sign, 15, 0);
        gotoxy(23, 2);
        if (err == -1)
            co_str("        ");
        else {
            co_str(qso.call_sign);
            }
        rstr_scr();
        }
    else {
        strcpy(qso.stop, time_of_day);
        co_str("END/ABORT QSO? ");
        while (((ch = toupper(getch())) != 'E') && (ch != 'A'));
        if (ch == 'A') {
            qso.call_sign[0] = 0;
            rstr_scr();
            gotoxy(23, 2);
            co_str("        ");
            }
        else {
            rstr_scr();
            build_window(5,11,15,73);
            do {
                err = complete_log_call();
                if (err == -1) {
                    gotoxy(13, 14);
                    co_str("REDO/ABORT LOG ENTRY? ");
                    while (((ch = toupper(getch())) != 'R') && (ch != 'A'));
                    }
                else
                    ch = 'C';
                }
            while (ch == 'R');
            if (ch == 'C') {
                log_file = fopen(my_log, "a");
                fwrite(&qso, sizeof(qso), 1, log_file);
                            close(log_file);
                }
            rstr_scr();
            }
        qso.call_sign[0] = 0;
        gotoxy(23, 2);
        co_str("        ");
        }
    }

int send_data()
{
    int err;
    char tempstr[80];

    /* Don't attemp to transmit file directly from RECEIVE mode */
    if (tx_flag == FALSE)
        return(0);
    co_str("FILE NAME: ");
    err = enter_str(tempstr, 50, 0);
    if ((err == -1) || (err == 0))
        return(0);
    send_file = fopen(tempstr, "r");
    if (send_file == 0) {
        gotoxy(13, 7);
        co_str("Unable to Open File: Press any key to continue");
        err = getch();
        return(0);
        }
    xmit_file(send_file);
    return(0);
    }

int xmit_file(fp)
FILE *fp;
{
    char str[80];
    char *err;

    err = fgets(str, 80, fp);
    co_tx(CR);
    lc_put(pk232_port, CR);
    while (err != NULL) {
        send_str(PK232, str);
        co_tx(CR);
        lc_put(pk232_port, CR);
        err = fgets(str, 80, fp);
        }
    co_tx(CR);
    lc_put(pk232_port, CR);
    close(fp);
    }

int xmit_eqp()
{
    int ch;
    
    /* Don't attemp to transmit file directly from RECEIVE mode */
    if (tx_flag == FALSE)
        return(0);
    send_file = fopen(my_equip, "r");
    if (send_file == 0) {
        build_window(5,11, 7, 73);
        gotoxy(13, 6);
        co_str("Unable to Open Equipment File: press any key to continue");
        getch();
        rstr_scr();
        return(0);
        }
    xmit_file(send_file);
    return(0);
    }

send_cmd(io_dev, str)
int io_dev;
char *str;
{
    co_tx(CR);
    co_tx_str("CMD: ");
    send_str(io_dev, str);
    }

/* send a character string to serial port (PK232 or TS440) */
send_str(io_dev, str)
int io_dev;
char *str;
{
    int i;

    i = 0;
    while (str[i]) {
        if (io_dev == PK232) {
            co_tx(str[i]);
            lc_put(pk232_port, str[i++]);
            }
        else
            lc_put(ts440_port, str[i++]);
        }
    }

int complete_log_call()
{
    int err;

    scr_scrup(0,cur_window.frow+1, cur_window.fcol+1,
                cur_window.trow-1, cur_window.tcol-1);
/*  Name */
    gotoxy(13, 6);
    co_str("NAME: ");
    err = enter_str(qso.name, 20, 0);
    if (err == -1)
        return(err);
/*  QTH  */
    gotoxy(13, 7);
    co_str("QTH: ");
    err = enter_str(qso.qth, 30, 0);
    if (err == -1)
        return(err);
/*  POWER */
    gotoxy(13, 8);
    co_str("POWER: ");
    err = enter_str(qso.power, 4, 0);
    if (err == -1)
        return(err);
/*  His RST  */
    gotoxy(13, 9);
    co_str("RST Sent: ");
    err = enter_str(qso.rst_sent, 3, 0);
    if (err == -1)
        return(err);
/*  My RST  */
    gotoxy(31, 9);
    co_str("RST Received: ");
    err = enter_str(qso.rst_rcvd, 3, 0);
    if (err == -1)
        return(err);
/*  Comments */
    gotoxy(13,10);
    co_str("COMMENTS: ");
    err = enter_str(qso.comments, 55, 0);
    if (err == -1)
        return(err);
/*  Contest Exchange */
    gotoxy(13, 11);
    co_str("CONTEST: ");
    err = enter_str(qso.contest, 20, 0);
    if (err == -1)
        return(err);
    return(0);
    }

/*
 scr_scrup(0,cur_window.frow+1, cur_window.fcol+1,
                cur_window.trow-1, cur_window.tcol-1);
*/

scr_scrup(int lines, int frow, int fcol, int trow, int tcol)
{
    union REGS regs;

    regs.h.ah = 6;
    regs.h.al = lines;
    regs.h.bh = 7;       /* normal video attribute  */
    regs.h.ch = frow;
    regs.h.cl = fcol;
    regs.h.dh = trow;
    regs.h.dl = tcol;

    int86(VIDEO, &regs, &regs);
    }

int scr_sinp()
{
    union REGS regs;

    regs.h.ah = 8;  /* read attribute and character at cursor */
    regs.h.bh = 0;
    int86(VIDEO, &regs, &regs);
    return (regs.h.al);
    }

co_str(str)
char *str;
{
    int i, x, y;
    int ch;

    i = getxy();
    y = 1 + (i >> 8);
    x = 1 + (i & 0xff);
    i = 0;
    while ((str[i] != 0) && (i < 80)) {
        if (ch == BS)
            gotoxy(--x, y);
        else {
            chr_out(str[i++]);
            gotoxy(++x, y);
            }
        }
   }

int getxy()
{
    union REGS regs;

    regs.h.ah = 3;  /* read cursor position into DH, DL */
    regs.h.bh = 0;
    int86(VIDEO, &regs, &regs);
    return (regs.x.dx);
    }
