UNIT Y767INST (* Y767 Instruction routines  D. J. Wilke N3HGQ 09/27/89 *);

INTERFACE

USES CRT, DOS, Y767GLO, Y767UTIL,
     Y767DISP, Y767COMM, Y767RTC;

PROCEDURE LoadMemories(MemFileToUse : STRING);
PROCEDURE SelectMemFile;
PROCEDURE SetUpSplit(Page,BarPos : INTEGER; FreqSet : STRING);
PROCEDURE SetVFO(Page,BarPos : INTEGER);
PROCEDURE Pager(Page,BarPos : INTEGER);
PROCEDURE LoadVFO(VFOFileToUse : STRING);
PROCEDURE SelectVFOFile;
PROCEDURE HGSelect;
PROCEDURE SetFreq;
PROCEDURE VFOMRSelect;
PROCEDURE MemSelect;
PROCEDURE ModeSelect;
PROCEDURE ProgStep;
PROCEDURE CTCSSToneSet;
PROCEDURE WhatWasThat(Param : String5; Col,Row : INTEGER);
PROCEDURE CatSend(Param : String5; StatusUpdateSize : INTEGER);
PROCEDURE StatusUpdate(Param : String86);
PROCEDURE TurnCatOn;
PROCEDURE TurnCatOff;
PROCEDURE CheckStatus(Inst : String5);
PROCEDURE QuickStat;
PROCEDURE MainFrame;
PROCEDURE MainMenu;
FUNCTION Offset(Page,BarPos : INTEGER) : STRING;

IMPLEMENTATION

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE LoadMemories(MemFileToUse : STRING);

VAR
    RecNo,DotPos,
    Result,BCDin     : INTEGER;
    Ok               : BOOLEAN;
    FreqChr          : STRING;
    Tone             : STRING[2];
    DispFreq         : STRING[7];
    FreqSet          : STRING[8];
    FreqString,
    LSDFreq          : STRING[10];
    Desc             : STRING[50];
    FreqTune         : REAL;
    Mode             : CHAR;

BEGIN (* LoadMemories *)
    WINDOW(2,6,79,23);
    PrMessage('Load memories from Datafile',4);
    CLRSCR;
    ASSIGN(Y767MemDataFile,MemFileToUse);
    {$I-} RESET(Y767MemDataFile) {$I+} ;
    Ok := (IOResult = 0);
    IF NOT Ok THEN BEGIN
        TEXTCOLOR(20);
        TEXTBACKGROUND(DBG);                 (* Error colors *)
        GOTOXY(20,6);
        WRITE('Cannot find FT-767 memory channel data file.');
        GOTOXY(20,7);
        WRITE('Memory channels will NOT be loaded.');
        GOTOXY(20,8);
        WRITE('Press return to continue.');
        Warble(1000,800);
        READLN;
    END (* IF NOT Ok *)
    ELSE BEGIN
        RecNo   := 0;
        FreqString := '';
        TEXTCOLOR(PFG);
        TEXTBACKGROUND(BLUE);              (* Special parameter colors *)
        GOTOXY(26,3);
        WRITE(' Using Datafile ');
        TEXTCOLOR(SFG);
        TEXTBACKGROUND(BLUE);              (* Filename colors *)
        WRITE(MemFileToUse,' ');
        TEXTCOLOR(DFG);
        TEXTBACKGROUND(DBG);               (* Default screen colors *)
        GOTOXY(5,5);
        WRITE('Memory   Frequency   Tone  ');
        GOTOXY(33,5);
        WRITE('Identifier, Description, Offset, Notes');
        PrLines('H',6,75,11,11,SBA,DBG,196); (* Display divider line *)
        PrLines('V',9,9,12,21,SBA,DBG,179);
        PrLines('V',26,26,12,21,SBA,DBG,179);
        PrLines('V',31,31,12,21,SBA,DBG,179);
        CatSend(Nul3String+CHR(0)+CHR(9),5); (* Load into VFO A *)
        FOR Index := 1 TO 9 DO BEGIN
            READLN(Y767MemDataFile);         (* Read past column titles *)
        END; (* FOR Index *)
        WHILE RecNo < 10 DO BEGIN
            FreqString := '';
            LSDFreq    := '';
            FreqSet    := '';
            TEXTCOLOR(PFG);
            TEXTBACKGROUND(DBG);             (* Parameter colors *)
            READLN(Y767MemDataFile,Y767MemFileParams);
            IF LENGTH(Y767MemFileParams) > 26 THEN BEGIN
                GOTOXY(6,RecNo + 7);
                FreqString    := COPY(Y767MemFileParams,1,8);
                Tone          := COPY(Y767MemFileParams,10,2);
                Mode          := Y767MemFileParams[13];
                DispFreq      := COPY(Y767MemFileParams,15,7);
                Desc          := COPY(Y767MemFileParams,25,50);
                GOTOXY(6,RecNo + 7);  WRITE(RecNo);
                GOTOXY(12,RecNo + 7); WRITE(DispFreq);
                GOTOXY(20,RecNo + 7); WRITE('MHz.');
                GOTOXY(27,RecNo + 7); WRITE(Tone);
                GOTOXY(33,RecNo + 7); WRITE(Desc);
                VAL(FreqString,FreqTune,Result);
                FreqTune := FreqTune/100000.0;
                CheckFreq(FreqTune);             (* Check if valid Freq *)
                LSDFreq  := MakeLSDMSD(FreqString,8);
                FreqSet  := FreqParm(LSDFreq,8);
                IF NOT FreqErrorFlag THEN BEGIN  (* Send the Freq to 767 *)
                    CatSend(MultString(3,NUL)+CHR(RecNo)+CHR($A),8); (*Sel Mem ch *)
                    CatSend(FreqSet+CHR(8),5);   (* Set the frequency *)
                    CASE Mode OF
                        'L' : Mode := CHR($10);
                        'U' : Mode := CHR($11);
                        'C' : Mode := CHR($12);
                        'A' : Mode := CHR($13);
                        'F' : Mode := CHR($14);
                        'K' : Mode := CHR($15);
                    END; (* CASE *)
                    CatSend(Nul3String+Mode+CHR($A),8); (* Set Mem Mode *)
                    CatSend(Nul3String+CHR($60)+CHR($A),86); (* Move to Mem *)
                END; (* IF NOT *)
            END; (* IF LENGTH *)
            INC(RecNo);
        END; (* WHILE RecNo *)
        CatSend(Nul3String+CHR(2)+CHR(9),5); (* Now, turn on MR *)
        WINDOW(1,1,80,25);
        Pause;
        PrFKeys;
        TEXTCOLOR(DFG);
        TEXTBACKGROUND(DBG);                 (* Default screen colors *)
    END; (* ELSE *)
END; (* LoadMemories *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SelectMemFile;

VAR
    MemoryProgramFile : CHAR;
    MemFileToUse      : STRING[12];

BEGIN (* SelectMemFile *)
    WINDOW(2,2,79,4);
    PrMessage('     Load Memories from Database File     ',3);
    WINDOW(2,6,79,23);
    CLRSCR;
    PrMessage('Choose a Memory Datafile:',2);
    GOTOXY(20,4);
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    WRITELN('1. Default FT-767GX memory setup program.');
    GOTOXY(20,5);
    WRITELN('2. HF/VHF Packet frequencies program.');
    GOTOXY(20,6);
    WRITELN('3. Two meter FM voice repeaters program.');
    GOTOXY(20,7);
    WRITELN('4. HAM HF/VHF CW subbands program.');
    GOTOXY(20,8);
    WRITELN('5. HAM HF/VHF/UHF phone subbands program.');
    GOTOXY(20,9);
    WRITELN('6. Commercial FAX frequencies program.');
    GOTOXY(20,10);
    WRITELN('7. Commercial RTTY frequencies program.');
    GOTOXY(20,11);
    WRITELN('8. Commercial AMTOR/SITOR frequencies program.');
    GOTOXY(55,2);
    MemoryProgramFile := READKEY;
    CASE MemoryProgramFile OF
        '1' : MemFileToUse := 'Y767DEF .MEM';
        '2' : MemFileToUse := 'Y767PAK .MEM';
        '3' : MemFileToUse := 'Y7672MR .MEM';
        '4' : MemFileToUse := 'Y767CWB .MEM';
        '5' : MemFileToUse := 'Y767PHB .MEM';
        '6' : MemFileToUse := 'Y767FAX .MEM';
        '7' : MemFileToUse := 'Y767RTY .MEM';
        '8' : MemFileToUse := 'Y767AMT .MEM';
    END; (* CASE *)
    LoadMemories(MemFileToUse);
END; (* SelectMemFile *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SetUpSplit(Page,BarPos : INTEGER; FreqSet : STRING);
(* Tune VFO B to repeater's INPUT Freq, VFO A to repeater's OUTPUT *)

BEGIN (* SetUpSplit *)
    CatSend(Nul3String+CHR(1)+CHR(9),5);     (* Set up to load VFO B *)
    CatSend(Offset(Page,BarPos)+CHR(8),5);   (* Set VFO B frequency *)
    CatSend(Nul3String+CHR(0)+CHR(9),5);     (* Set up to load VFO A *)
    CatSend(FreqSet+CHR(8),5);               (* Set VFO A frequency *)
    IF (ORD(Update[1])) AND ($08) = 0 THEN   (* Mask off Split bit *)
        CatSend(SplitTog,26);                (* Toggle Split on, if off *)
END; (* SetUpSplit *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SetVFO(Page,BarPos : INTEGER);

VAR
    FreqSet    : STRING[8];
    LSDFreq    : STRING[8];
    FreqString : STRING[8];
    Result     : INTEGER;
    Mode       : CHAR;
    FreqTune   : REAL;

BEGIN (* SetVFO *)
    FreqString  := COPY(MemArray[Page *10 +BarPos],1,8);
    VAL(FreqString,FreqTune,Result);
    FreqTune := FreqTune/100000.0;
    IF COPY(MemArray[Page *10 +BarPos],1,8) <> '        ' THEN BEGIN
        LSDFreq := MakeLSDMSD(COPY(MemArray[Page *10 +BarPos],1,8),8);
        FreqSet := FreqParm(LSDFreq,8);
        Mode    := MemArray[Page *10 +BarPos,13];
        CASE Mode OF
            'L' : Mode := CHR($10);
            'U' : Mode := CHR($11);
            'C' : Mode := CHR($12);
            'A' : Mode := CHR($13);
            'F' : Mode := CHR($14);
            'K' : Mode := CHR($15);
        END; (* CASE *)
        CheckFreq(FreqTune);                 (* Check if within valid range *)
        IF NOT FreqErrorFlag THEN BEGIN
            CatSend(MultString(3,NUL)+Mode+CHR($A),8); (* Set the Mode *)
            IF COPY(MemArray[Page *10 +BarPos],23,1) = '-' THEN
                SetUpSplit(Page,BarPos,FreqSet); (* Load VFO with minus offset *)
            IF COPY(MemArray[Page *10 +BarPos],23,1) = '+' THEN
                SetUpSplit(Page,BarPos,FreqSet); (* Load VFO with plus offset *)
            IF COPY(MemArray[Page *10 +BarPos],23,1) = ' ' THEN BEGIN
                CatSend(Aclr,26);            (* Turn off SPLIT/CLAR/OFFSET *)
                CatSend(Nul3String+CHR(0)+CHR(9),5); (* Set up to load VFO A *)
                CatSend(FreqSet+CHR(8),5);   (* Set VFO A frequency *)
            END; (* IF *)
            TEXTCOLOR(SFG);
            TEXTBACKGROUND(DBG);             (* Selected Freq colors *)
            PrDfPage(Page,Page *10 +BarPos,1); (* Place bar *)
            CatSend(Check,86);               (* Get new parameters *)
            QuickStat;                       (* Display new Freq *)
            WINDOW(5,12,79,22);              (* Back to paging window *)
            GOTOXY(1,BarPos);                (* Put cursor at beg of line *)
            Peep(2000);                      (* Give audible signal *)
        END; (* IF NOT *)
    END; (* IF *)
END; (* SetVFO *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE Pager(Page,BarPos : INTEGER);

BEGIN (* Pager *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(DBG);                     (* Requested param colors *)
    CLRSCR;                                  (* Remove all old entries *)
    PrDfPage(Page,0,10);                     (* Put up 10 line page *)
    TEXTCOLOR(BFG);
    TEXTBACKGROUND(BBG);                     (* Selection bar colors *)
    PrDfPage(Page,Page *10 +BarPos,1);       (* Put bar on 1 or 10 *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(DBG);                     (* Requested param colors *)
    GOTOXY(1,BarPos);                        (* Put cursor at beg of line *)
END; (* Pager *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE LoadVFO(VFOFileToUse : STRING);

VAR
    RecNo,Page,
    Xpos,BarPos,
    Result,BCDin     : INTEGER;
    Ok,Fk,Display    : BOOLEAN;
    Choice           : CHAR;

BEGIN (* LoadVFO *)
    WINDOW(2,6,79,23);
    PrMessage('Load VFO A from Datafile',4);
    CLRSCR;
    ASSIGN(Y767VFODataFile,VFOFileToUse);
    {$I-} RESET(Y767VFODataFile) {$I+} ;
    Ok := (IOResult = 0);
    IF NOT Ok THEN BEGIN
        TEXTCOLOR(20);
        TEXTBACKGROUND(DBG);                 (* Error colors *)
        GOTOXY(20,6);
        WRITE('Cannot find FT-767 VFO database file.');
        GOTOXY(20,7);
        WRITE('VFO A will NOT be loaded.');
        GOTOXY(20,8);
        WRITE('Press return to continue.');
        Warble(1000,800);
        READLN;
    END (* IF NOT Ok *)
    ELSE BEGIN                               (* File read OK, get data *)
        RecNo      := 0;
        Page       := 0;
        Display    := TRUE;                  (* Display pages of datafile *)
        Xpos       := 5;
        BarPos     := 1;                     (* Bar at top on page 0 *)
        TEXTCOLOR(PFG);
        TEXTBACKGROUND(BLUE);                (* Special parameter colors *)
        GOTOXY(26,3);
        WRITE(' Using Datafile ');
        TEXTCOLOR(SFG);
        TEXTBACKGROUND(BLUE);                 (* Filename colors *)
        WRITE(VFOFileToUse,' ');
        TEXTCOLOR(DFG);
        TEXTBACKGROUND(DBG);                 (* Default screen colors *)
        GOTOXY(2,18);
        WRITE('  <Page Up>  <Page Down>  <',CHR(24),',',CHR(25));
        WRITE('> to select  <',CHR(17),CHR(196),CHR(217),'> to set VFO  <End> to exit');
        GOTOXY(5,5);
        WRITE('Record  Freq   Ofs  Mode   ');
        GOTOXY(33,5);
        WRITE('Identifier, Description, Notes');
        PrLines('H',6,75,11,11,SBA,DBG,196); (* Display divider line *)
        FILLCHAR(MemArray,SIZEOF(MemArray),' '); (* Initialize array *)
        FOR Index := 1 TO 9 DO BEGIN
           READLN(Y767VFODataFile);          (* Read past column titles *)
        END; (* FOR Index *)
        WINDOW(5,12,79,22);                  (* Paging window *)
        WHILE NOT EOF(Y767VFODataFile) DO BEGIN
            TEXTCOLOR(PFG);
            TEXTBACKGROUND(DBG);             (* Parameter colors *)
            INC(RecNo);
            READLN(Y767VFODataFile,Y767MemFileParams);
            (* Make bar length = 70 characters for valid entries *)
            IF (LENGTH(Y767MemFileParams) < 70) THEN BEGIN
                Y767MemFileParams := Y767MemFileParams
                + MultString(70 - LENGTH(Y767MemFileParams),' ');
            END; (* IF *)
            MemArray[RecNo] := Y767MemFileParams;
        END; (* WHILE NOT EOF*)
        CLRSCR;
        PrDfPage(Page,0,10);                 (* Display Page 0 *)
        GOTOXY(1,BarPos);
        TEXTCOLOR(BFG);
        TEXTBACKGROUND(BBG);
        PrDfPage(Page,Page *10 +BarPos,1);   (* Put bar on 1st entry *)
        GOTOXY(1,BarPos);
        WHILE Display DO BEGIN
            REPEAT
                InKey(Fk,Choice);
            UNTIL (Choice IN [#72..#82])
               OR (Choice = #13);
            CASE Choice OF
                 #13 : SetVFO(Page,BarPos);                   (* <Enter> *)
                 #72 : BEGIN                                  (* Cursor Up *)
                           DEC(BarPos);
                           IF BarPos = 0 THEN BEGIN           (* At top? *)
                               BarPos := 10;                  (* Then rollover *)
                               DEC(Page);
                               IF Page < 0 THEN Page := 9;
                               Pager(Page,BarPos);
                           END;
                           TEXTCOLOR(PFG);
                           TEXTBACKGROUND(DBG);
                           GOTOXY(1,BarPos);
                           TEXTCOLOR(BFG);
                           TEXTBACKGROUND(BBG);
                           PrDfPage(Page,Page *10 +BarPos,1); (* Place bar *)
                           TEXTCOLOR(PFG);
                           TEXTBACKGROUND(DBG);
                           IF BarPos = 10 THEN
                               PrDfPage(Page,Page *10 +1,1)   (* Remove old bar at top *)
                           ELSE
                               PrDfPage(Page,Page *10 +BarPos +1,1); (* Else old bar *)
                           GOTOXY(1,BarPos);
                       END;
                 #73 : BEGIN                                  (* Page UP *)
                           DEC(Page);
                           IF Page < 0 THEN Page := 9;
                           BarPos := 10;
                           Pager(Page,BarPos);
                       END;
                 #79 : Display := FALSE;                      (* End *)
                 #80 : BEGIN                                  (* Cursor Down *)
                           INC(BarPos);
                           IF BarPos = 11 THEN BEGIN          (* At bottom? *)
                               BarPos := 1;                   (* Then rollover *)
                               INC(Page);
                               IF Page = 10 THEN Page := 0;
                               Pager(Page,BarPos);
                           END;
                           TEXTCOLOR(PFG);
                           TEXTBACKGROUND(DBG);
                           GOTOXY(1,BarPos);
                           TEXTCOLOR(BFG);
                           TEXTBACKGROUND(BBG);
                           PrDfPage(Page,Page *10 +BarPos,1); (* Place bar *)
                           TEXTCOLOR(PFG);
                           TEXTBACKGROUND(DBG);
                           IF BarPos = 1 THEN
                               PrDfPage(Page,Page *10 +10,1)  (* Remove old bar at bot *)
                           ELSE
                               PrDfPage(Page,Page *10 +BarPos -1,1); (* Else old bar *)
                           GOTOXY(1,BarPos);
                       END;
                 #81 : BEGIN                                  (* Page Down *)
                           INC(Page);
                           IF Page = 10 THEN Page := 0;
                           BarPos := 1;
                           Pager(Page,BarPos);
                       END; (* #81 *)
            END; (* CASE *)
        END; (* WHILE Display *)
    END; (* ELSE *)
    WINDOW(2,6,79,23);
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
END; (* LoadVFO *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SelectVFOFile;

VAR
    VFOProgramFile : CHAR;
    VFOFileToUse   : STRING[12];

BEGIN (* SelectVFOFile *)
    WINDOW(2,2,79,4);
    PrMessage('     Load VFO A from Database File     ',3);
    WINDOW(2,6,79,23);
    CLRSCR;
    PrMessage('Choose a VFO Datafile:',2);
    GOTOXY(20,4);
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    WRITELN('1. Two Meter FM Voice Repeaters.');
    GOTOXY(20,5);
    WRITELN('2. RTTY press frequencies 2.024 - 14.565 MHz.');
    GOTOXY(20,6);
    WRITELN('3. RTTY press frequencies 14.568 - 19.280 MHz.');
    GOTOXY(20,7);
    WRITELN('4. RTTY press frequencies 19.565 - 25.337 MHz.');
    GOTOXY(20,8);
    WRITELN('5. International Shortwave  2.000 - 11.500 MHz.');
    GOTOXY(20,9);
    WRITELN('6. International Shortwave 11.600 - 28.000 MHz.');
    GOTOXY(20,10);
    WRITELN('7. 25 Meter Shortwave Band 11.700 - 11.975 MHz.');
    GOTOXY(20,11);
    WRITELN('8. 31 Meter Shortwave Band  9.500 -  9.775 MHz.');
    GOTOXY(20,12);
    WRITELN('9. AM Broadcast Band 0.550 - 1.600 MHz.');
    GOTOXY(55,2);
    VFOProgramFile := READKEY;
    CASE VFOProgramFile OF
        '1' : VFOFileToUse := 'Y7672MR .DAT';
        '2' : VFOFileToUse := 'Y767TTA .DAT';
        '3' : VFOFileToUse := 'Y767TTB .DAT';
        '4' : VFOFileToUse := 'Y767TTC .DAT';
        '5' : VFOFileToUse := 'Y767SWA .DAT';
        '6' : VFOFileToUse := 'Y767SWB .DAT';
        '7' : VFOFileToUse := 'Y76725M .DAT';
        '8' : VFOFileToUse := 'Y76731M .DAT';
        '9' : VFOFileToUse := 'Y767AMB .DAT';
    END; (* CASE *)
    LoadVFO(VFOFileToUse);
END; (* SelectVFOFile *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE HGSelect (* Select between Ham or General coverage bands *);

VAR
    HGS,CovSel : CHAR;

BEGIN (* HgSelect *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('Ham/General Coverage Screen',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    PrBandLimits;                            (* Display band limits table *)
    (* Display headings & draw `Band Mode' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(56,1); WRITE ('     Band Mode     ');
    PrBox;                                   (* Draw `H/G Select' box *)
    (* Prompt for Ham or General coverage *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(11,1); WRITE('H');
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WRITE(' = Ham Bands, ');
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    WRITE('G');
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WRITE(' = General Coverage');
    GOTOXY(11,3); WRITE('Enter H or G.');
    GOTOXY(25,3); WRITE(CHR(198));
    FOR Index := 1 TO 29 DO
        WRITE(CHR(205));
    WRITE(CHR(16));
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);                 (* Requested parameter colors *)
        GOTOXY(58,3); WRITE ('       ?        ');
        GOTOXY(65,3);
        REPEAT
            CovSel := UPCASE(ReadKey);
        UNTIL (CovSel = 'H') OR (CovSel = 'G');
        GOTOXY(58,3);
        IF CovSel = 'H' THEN BEGIN
            HGS := CHR(32);
            WRITE('   Ham Bands    ');
        END (* IF Covsel *)
        ELSE BEGIN
            HGS := CHR(33);
            WRITE('  Gen Coverage  ');
        END; (* ELSE *)
    END; (* IF SetSel *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    CatSend(Nul3String+HGS+CHR($A),26);
    MainMenu;
END; (* HgSelect *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SetFreq;
(* Get frequency, build BCD Hex string for use in CatSend Subroutine *)

VAR
    FreqString,LSDFreq,FreqSet : STRING[10];
    MHzString,KHzString : STRING[10];
    FreqInt : STRING[8];
    FreqTrans : STRING;
    FreqTune : REAL;
    DotPos,Result,BCDIn,MHz,KHz,Hz : INTEGER;

BEGIN (* SetFreq *)
    FreqString := '';                        (* Initialize variables *)
    MHzString  := '';
    KHzString  := '';
    FreqTune   := 0.0;
    FreqInt    := '';
    LSDFreq    := '';
    FreqSet    := '';
    DotPos     := 0;
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('           Set Frequency Screen            ',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    (* Display headings & draw `Operating Frequency' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(56,1); WRITE('Operating Frequency');
    PrBox;                                   (* Draw `Op Freq' box *)
    IF SetSel THEN PrBandLimits;             (* Display band limits table *)
    (* Prompt for desired frequency *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    GOTOXY(11,3); WRITE('Enter desired frequency.');
    GOTOXY(36,3); WRITE(CHR(198));
    FOR Index := 1 TO 18 DO
        WRITE(CHR(205));
    WRITE(CHR(16));
    GOTOXY(69,3); WRITE('MHz.');
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);                 (* Requested parameter colors *)
        GOTOXY(59,3); WRITE('         ');
        GOTOXY(59,3);
        READLN(FreqString);
    END
    ELSE FreqString := ('145.03075');
    VAL(FreqString,FreqTune,Result);         (* Freq is REAL number *)
    CheckFreq(FreqTune);
    IF NOT FreqErrorFlag THEN BEGIN
        GOTOXY(57,3);                        (* Set up `Op Freq' box *)
        WRITE(FreqTune:10:5);                (* Display Freq in box *)
        (* Pad Freq with leading and trailing zeros, if necessary *)
        DotPos := Pos('.',FreqString);
        DELETE(FreqString,DotPos,1);
        IF DotPos = 0 THEN DotPos := LENGTH(FreqString) + 1;
        FreqInt := MultString(4 - DotPos,'0')
            + FreqString + MultString(8 - LENGTH(FreqInt),'0');
        LSDFreq := MakeLSDMSD(FreqInt,8);
        FreqSet := FreqParm(LSDFreq,8);
        IF NOT SetSel THEN BEGIN
            GOTOXY(19,12); WRITE(LENGTH(FreqString),'  Positions.');
            GOTOXY(10,13); WRITE(FreqTune:10:5,'  MHz. (FreqTune)');
            GOTOXY(12,14); WRITE(FreqInt,'  Normal BCD (FreqInt)');
            GOTOXY(12,15); WRITE(LSDFreq,'  Inverted BCD (LSDFreq)');
            GOTOXY(13,16); WRITE(COPY(FreqSet,1,1));
            GOTOXY(15,16); WRITE(COPY(FreqSet,2,1));
            GOTOXY(17,16); WRITE(COPY(FreqSet,3,1));
            GOTOXY(19,16); WRITE(COPY(FreqSet,4,1));
            GOTOXY(22,16); WRITE('BCD string LSD->MSD (FreqSet)');
            Pause;
        END; (* NOT SetSel *)
    (* Send the Frequency to 767 *)
    CatSend(MultString(4,Nul) + CHR(9),5);   (* Turn off Mem mode 1st *)
    CatSend(FreqSet + CHR(8),5);             (* Set the frequency *)
    END; (* IF NOT *)
    MainMenu;
END; (* SetFreq *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE VFOMRSelect;
(* Select between VFOs and Memory *)

VAR
    VMS,VMSel : CHAR;

BEGIN (* VFOMRSelect *)
    VMS := CHR(0);                           (* Initialize variables *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('Select VFO/Memory Screen',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    (* Display headings & draw `Operating Frequency' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(57,1); WRITE('     Selected      ');
    PrBox;
    (* Prompt for VFO A, VFO B or Memory *)
    GOTOXY(11,1); WRITE('A=VFO A, B=VFO B, M=Memory');
    GOTOXY(11,3); WRITE('Enter A, B, or M.');
    GOTOXY(29,3); WRITE(CHR(198));
    FOR Index := 1 TO 25 DO
        Write(CHR(205));
    WRITE(CHR(16));
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);                 (* Requested parameter colors *)
        GOTOXY(60,3); WRITE('     ?    ');
        GOTOXY(65,3);
        VMSel := UPCASE(ReadKey);
        CASE VMSel OF
            'A' : BEGIN
                  VMS := CHR(0);
                  GOTOXY(60,3); WRITE('  VFO  A  ');
                  END;
            'B' : BEGIN
                  VMS := CHR(1);
                  GOTOXY(60,3); WRITE('  VFO  B  ');
                  END;
            'M' : BEGIN
                  VMS := CHR(2);
                  GOTOXY(60,3); WRITE('  MEMORY  ');
                  END;
        END; (* CASE *)
    END; (* IF SetSel *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    CatSend(Nul3String+VMS+CHR(9),5);        (* Set VFOs or Mem *)
    MainMenu;
END; (* VFOMRSelect *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE MemSelect;
(* Select memory channel *)

VAR
    MemCh,MCH : CHAR;
    MemAddr   : INTEGER;
    MemFreq   : REAL;

BEGIN (* MemSelect *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('Select Memory Screen',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    PrMessage('Current Memory Parameters ',5); (* Display Mem Chan headings *)
    GOTOXY(13,6); WRITE(' Channel');
    GOTOXY(29,6); WRITE('Frequency');
    GOTOXY(48,6); WRITE('Mode');
    GOTOXY(62,6); WRITE('Tone');
    PrLines('H',6,75,12,12,SBA,DBG,196);     (* Display divider line *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    FOR Index := 0 TO 9 DO BEGIN             (* Display Memory channel numbers *)
        GOTOXY(12,Index + 8);
        WRITE('Memory 0');
        WRITE(Index);
    END;
    PrMem(27,86,8,27,49,59); (* Display channel data from Update stream *)
    (* Display headings & draw `Selected Memory' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(58,1); WRITE('Selected Memory');
    PrBox;                                   (* Draw `Memory Select' box *)
    (* Prompt for desired memory number *)
    GOTOXY(11,3); WRITE('Enter desired memory.');
    GOTOXY(33,3); WRITE(CHR(198));
    FOR Index := 1 TO 21 DO
        WRITE(CHR(205)); WRITE(CHR(16));
    GOTOXY(60,3); WRITE('Channel');
    IF SetSel THEN
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(69,3); WRITE('  ');
    REPEAT
        MemCh := (ReadKey);
    UNTIL MemCh IN [#48..#57];
    (* Display Channel # in `Selected Memory' box *)
    GOTOXY(69,3); WRITE('0',MemCh);
    MCH := CHR((ORD(MemCh) - 48));           (* Compute Bin value *)
    MemAddr := (ORD(MemCh) - 48) * 6 + 27;   (* Compute Addr in Update stream *)
    GOTOXY(59,3); WRITE('            ');
    (* Display Memory Channel Frequency in `Selected Memory' box *)
    PrFreq(Update,MemAddr,59,3); (* Display Mem Freq from Update stream *)
    CatSend(Nul3String+MCH+CHR($A),8);       (* Set the channel *)
    CatSend(Nul3String+CHR(2)+CHR(9),5);     (* Switch mode to MR *)
    MainMenu;
END; (* MemSelect *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE ModeSelect (* Select operating Mode *);

VAR
    ModeSel : CHAR;
    Mode    : STRING;

BEGIN (* ModeSelect *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('Select Mode Screen',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    (* Display headings & draw `Mode' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(58,1); WRITE('Selected Memory');
    GOTOXY(56,1); WRITE('       Mode        ');
    PrBox;                                   (* Draw `Mode Select' box *)
    (* Prompt for VFO A, VFO B or Memory *)
    GOTOXY(11,1); WRITE('L=LSB, U=USB, C=CW, A=AM, F=FM, K=FSK');
    GOTOXY(11,3); WRITE('Enter L, U, C, A, F, or K.');
    GOTOXY(38,3); WRITE(CHR(198));
    FOR Index := 1 to 16 DO
        WRITE(CHR(205));
    WRITE(CHR(16));
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);                 (* Requested parameter colors *)
        GOTOXY(60,3); WRITE ('     ?    ');
        GOTOXY(65,3);
        REPEAT
            ModeSel := UPCASE(ReadKey);
            CASE ModeSel OF
                'L' : BEGIN
                      Mode := CHR($10);
                      GOTOXY(60,3); WRITE(' Lower SB ');
                      END;
                'U' : BEGIN
                      Mode := CHR($11);
                      GOTOXY(60,3); WRITE(' Upper SB ');
                      END;
                'C' : BEGIN
                      Mode := CHR($12);
                      GOTOXY(60,3); WRITE('    CW    ');
                      END;
                'A' : BEGIN
                      Mode := CHR($13);
                      GOTOXY(60,3); WRITE('    AM    ');
                      END;
                'F' : BEGIN
                      Mode := CHR($14);
                      GOTOXY(60,3); WRITE('    FM    ');
                      END;
                'K' : BEGIN
                      Mode := CHR($15);
                      GOTOXY(60,3); WRITE('    FSK   ');
                      END;
            END; (* Case *)
        UNTIL (ModeSel = 'L') OR (ModeSel = 'U') OR (ModeSel = 'C') OR
              (ModeSel = 'A') OR (ModeSel = 'F') OR (ModeSel = 'K');
        TEXTCOLOR(DFG);
        TEXTBACKGROUND(DBG);                 (* Default screen colors *)
        CatSend(Nul3String+Mode+CHR($A),8);  (* Set the Mode *)
        MainMenu;
    END; (* IF SetSel *)
END; (* ModeSelect *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE ProgStep;
(* Set step size for Programmed frequency Step Up/Down *)

VAR
    StepSet, StepFreq   : STRING[6];
    LSDStep             : STRING[6];
    StepInt             : STRING[4];
    StepChr             : STRING;
    Result,BCDin,DotPos : INTEGER;
    TuneStep            : REAL;

BEGIN (* ProgStep *)
    LSDStep  := '';
    StepFreq := '';
    StepInt  := '';
    StepSet  := '';
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    IF DownFlag THEN
        PrMessage('Set Increment for Frequency Step DOWN',4)
    ELSE
        PrMessage('Set Increment for Frequency Step UP',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    (* Display headings & draw `Programmed Step Size' box *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(56,1); WRITE('Programmed Step Size');
    PrBox;                                   (* Draw `Step Size' box *)
    GOTOXY(11,3); WRITE('Enter desired Step Size.');
    GOTOXY(36,3); WRITE(CHR(198));
    FOR Index := 1 TO 18 DO
        WRITE(CHR(205));
    WRITE(CHR(16));
    GOTOXY(67,3); WRITE('KHz.');
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);             (* Requested parameter colors *)
        GOTOXY(61,3); WRITE('     ');
        GOTOXY(61,3); READLN(StepFreq);
    END
    ELSE StepFreq := '12.34';
    VAL(StepFreq,TuneStep,Result);
{   IF (StepFreq < 0) OR (StepFreq > 99) THEN
        ErrorAlarm(FreqErr$, 10, 58): GOTO GetStep }
    (* Display Step in `Programmed Step Size' box *)
    GOTOXY(61,3); WRITE(TuneStep:4:2);
    DotPos := Pos('.',StepFreq);
    DELETE(StepFreq,DotPos,1);
    IF DotPos = 0 THEN
        DotPos := LENGTH(StepFreq) +1;
    (* Pad StepFreq with appropriate leading zeros *)
    CASE DotPos OF
        1 : StepInt := '00' + StepFreq;
        2 : StepInt := '0'  + StepFreq;
        3 : StepInt := StepFreq;
    END; (* CASE *)
    CASE LENGTH(StepInt) OF
        1 : StepInt := StepInt + '000';
        2 : StepInt := StepInt + '00';
        3 : StepInt := StepInt + '0';
    END; (* CASE *)
    (* Construct 4 byte LSDStep string (LSD -> MSD) *)
    Index := 4;
    WHILE Index <> 0 DO BEGIN
        LSDStep := LSDStep + COPY(StepInt,Index - 1,2);
        Index := Index - 2;
    END;
    (* Convert LSDStep to 2 hex bytes *)
    Index := 1;
    WHILE Index < 4 DO BEGIN
        StepChr := COPY(LSDStep,Index,2);
        VAL(StepChr,BCDin,Result);
        Index := Index + 2;
        StepSet := StepSet + Translate(BCDin);
    END; (* WHILE Index *)
    IF SetSel = FALSE THEN BEGIN
        GOTOXY(13,12); WRITE(LENGTH(StepFreq),'  Positions.');
        GOTOXY(10,13); WRITE(TuneStep:4:2,' KHz.');
        GOTOXY(10,14); WRITE(StepInt,'  Normal BCD');
        GOTOXY(10,15); WRITE(LSDStep,'  Inverted BCD');
        GOTOXY(11,16); WRITE(COPY(StepSet,1,1));
        GOTOXY(13,16); WRITE(COPY(StepSet,2,1));
        GOTOXY(16,16); WRITE('StepSet binary string.');
        Pause;
    END; (* IF SetSel *)
    CatSend(Nul3String+CHR(0)+CHR(9),5);     (* First turn off Mem mode *)
    IF DownFlag THEN
        CatSend(CHR(0)+CHR(0)+StepSet+CHR(5),5)  (* Set step DN *)
    ELSE
        CatSend(CHR(0)+CHR(0)+StepSet+CHR(4),5); (* Set step UP *)
    MainMenu;
END; (* ProgStep *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE CTCSSToneSet;

VAR
    ToneSet,ToneFreq : STRING[8];
    Tone             : REAL;
    Result           : INTEGER;

BEGIN (* CTCSSToneSet *)
    ToneSet := ''; ToneFreq := '';           (* Initialize collection strings *)
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('CTCSS Tones Screen',4);
    WINDOW(2,6,79,23);
    CLRSCR;
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(56,1); WRITE('CTCSS Tone Frequency'); (* Display headings *)
    PrBox;                                   (* Draw `CTCSS Tone' box *)
    (* Display CTCSS valid frequencies table *)
    GOTOXY(17,6); WRITE('67.0           123.0          186.2         C77.0');
    GOTOXY(17,7); WRITE('71.9           127.3          192.8         C79.7');
    GOTOXY(17,8); WRITE('77.0           131.8          203.5         C82.5');
    GOTOXY(17,9); WRITE('82.5           136.5          210.7         C85.4');
    GOTOXY(17,10); WRITE('88.5           141.3          218.1         C88.5');
    GOTOXY(17,11); WRITE('94.8           146.2          225.7         C91.5');
    GOTOXY(17,12); WRITE('100.0          151.4          233.6');
    GOTOXY(17,13); WRITE('103.5          156.7          241.8');
    GOTOXY(17,14); WRITE('107.2          162.2          250.3     `C'' tones have');
    GOTOXY(17,15); WRITE('110.9          167.9          C67.0       high Q (80)');
    GOTOXY(17,16); WRITE('114.8          173.8          C71.9');
    GOTOXY(17,17); WRITE('118.8          179.9          C74.7');
    (* Prompt for desired frequency *)
    GOTOXY(7,3); WRITE('Enter CTCSS Tone from table.');
    GOTOXY(36,3); WRITE(CHR(198));
    FOR Index := 1 TO 18 DO
        WRITE(CHR(205));
    WRITE(CHR(16));
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    GOTOXY(68,3); WRITE ('Hz.');
    IF SetSel THEN BEGIN
        TEXTCOLOR(RFG);
        TEXTBACKGROUND(DBG);                 (* Requested parameter colors *)
        GOTOXY(61,3); WRITE('     ');
        GOTOXY(61,3); READLN(ToneFreq);
    END
    ELSE ToneFreq := ('131.8');
    VAL(ToneFreq,Tone,Result);
{   IF (Tone < 67) OR (Tone > 250.3) THEN
        ErrorAlarm(FreqErr$, 8, 58): GOTO GetTone }
    (* Display Tone Frequency in `CTCSS Tone Frequency' box *)
    GOTOXY(61,3); WRITE(Tone:3:1);
    (* Send instruction to 767 *)
    (* Set to zero for now, need routine here *)
{   ToneSet := CHR(0)+CHR(0)+CHR(0)+CHR(0)+CHR($C);
    CatSend(ToneSet,5);                      (* Set the tone frequency *)
    Pause; }
    PrFKeys;
    MainMenu;
END; (* CTCSSToneSet *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE WhatWasThat(Param : String5; Col,Row : INTEGER);
(* Display Instruction/Echo as sent from computer/FT-767 *)

VAR
    MSN,Result : INTEGER;

BEGIN (* WhatWasThat *)
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(DBG);                     (* Returned status colors *)
    GOTOXY(Col,Row);
    FOR Index := 1 TO LENGTH(Param) DO BEGIN
        VAL(Param[Index],MSN,Result);
        WriteHex(ORD(Param[Index]));
        WRITE(' ');                          (* Display as BCD Hex values *)
    END;
END; (* WhatWasThat *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE CatSend(Param : String5; StatusUpdateSize : INTEGER);
(* Send Instruction string to 767, get Echo & send ACKnowledge *)

VAR
    Temp  : STRING[86];
    Ch    : CHAR;

BEGIN (* CatSend *)
    Inst := Param;                           (* Inform Global variable *)
    Echo := '     ';
    ClockFlag := FALSE;                      (* No clock during Comm *)
    SendString(Param,15);                    (* Send Instruction to 767 *)
(* Get 5 character echo from 767, if a match, send ACK string to 767 *)
    IF Test THEN
        FOR Index := 1 TO 5 DO
    Echo[Index] := Inst[Index]               (* Simulate 767 echo *)
    ELSE FOR Index := 1 TO 5 DO
        Echo[Index] := InChar;               (* Get real echo from 767 *)
    IF (Echo = Inst) AND (NOT Test) THEN BEGIN
        (* If Test was TRUE, UPDATE.DAT provided a simulated Update *)
        SendString(AckString,StatusUpdateSize); (* Echo matches, send ACK *)
        FOR Index := 1 TO StatusUpdateSize DO
            Lifo[Index] := InChar;           (* Get real Update from 767 *)
            (* Update stream from 767 is sent last byte first *)
        Temp := Fifo(Lifo);                  (* Convert LIFO to FIFO *)
        Update := Temp;
    END (* IF Echo *)
    ELSE IF Echo <> Inst THEN BEGIN
        WINDOW(2,6,79,23);
        ErrorAlarm(CmdErr,0,7);              (* Issue command error warning *)
        Warble(3000,2400);
        GOTOXY(31,9);  WRITE('Inst:');
        GOTOXY(31,10); WRITE('Echo:');
        WhatWasThat(Inst,38,9);
        WhatWasThat(Echo,38,10);
        FlushBuffer;                         (* Clear buffer of trash *)
        Pause;
        WINDOW(2,6,79,23);
        CLRSCR;
        PrFKeys;
    END; (* ELSE IF *)
    ClockFlag := TRUE;                       (* Reinstate RTC *)
END; (* CatSend *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE StatusUpdate(Param : String86);
(* Display all radio parameters *)

BEGIN
    PrFrame(1,80,1,24);                      (* Draw main frame *)
    TEXTCOLOR(DFG);                          (* Display headers *)
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    WINDOW(1,1,80,5);
    PrMessage('Status Update Screen', 4);
    GOTOXY(3,2); WRITE('LSD        MSD ');
    WhatWasThat(Inst,3,3);                   (* Display Instr as sent *)
    WhatWasThat(Echo,3,4);                   (* Display Echo as received *)
    WINDOW(2,6,79,23);
    CLRSCR;
    PrRule; (* Draw inside ruling lines for status screen *)
    ScreenWrite(CHR(209),18,1,SBA);          (* Dbl/sing tee, top *)
    PrLines('V',18,0,2,4,SBA,DBG,179);       (* Sing V left side *)
    ScreenWrite(CHR(207),18,5,SBA);          (* Dbl/sing tee, bot *)
    ScreenWrite(CHR(209),63,1,SBA);          (* Dbl/sing tee, top *)
    PrLines('V',63,0,2,4,SBA,DBG,179);       (* Sing V right side *)
    ScreenWrite(CHR(207),63,5,SBA);          (* Dbl/sing tee, bot *)
    PrLines('H',3,50,7,0,SBA,DBG,196);       (* Sing H line, mid top *)
    PrLines('H',3,50,9,0,SBA,DBG,196);       (* Sing H line, mid top *)
    PrLines('H',3,50,11,0,SBA,DBG,196);      (* Sing H line, mid top *)
    ScreenWrite(CHR(199),1,13,SBA);          (* Dbl/sing tee, left *)
    PrLines('H',2,79,13,0,SBA,DBG,196);      (* Sing H line, midscreen *)
    ScreenWrite(CHR(182),80,13,SBA);         (* Dbl/sing tee, right *)
    ScreenWrite(CHR(209),52,5,SBA);          (* Dbl/sing tee, top *)
    PrLines('V',52,0,6,12,SBA,DBG,179);      (* Sing V midscreen, top *)
    ScreenWrite(CHR(197),52,13,SBA);         (* Sing cross *)
    PrLines('V',52,0,14,23,SBA,DBG,179);     (* Sing V midscreen, bot *)
    ScreenWrite(CHR(207),52,24,SBA);         (* Dbl/sing tee, bot *)
    PrLines('H',54,78,15,0,SBA,DBG,196);     (* Sing H line, mid bot *)
    (* UPPER LEFT QUADRANT *)
    TEXTCOLOR(DFG);                          (* Display headings *)
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    GOTOXY(3,1); WRITE ('Function');
    GOTOXY(16,1); WRITE ('Frequency');
    GOTOXY(31,1); WRITE ('Mode');
    GOTOXY(42,1); WRITE ('Tone');
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(DBG);                     (* Parameter screen colors *)
    GOTOXY(2,7); WRITE ('Clarifier');
    GOTOXY(4,3); WRITE ('VFO A');
    GOTOXY(4,5); WRITE ('VFO B');
    (* Display returned status for VFO A, VFO B, Clarifier *)
    IF LENGTH(Update) >= 26 THEN BEGIN
        PrFreq(Param,15,13,3);               (* VFO A *)
        PrCTCSS(Param,19,39,3);
        PrMode(Param,20,31,3);
        PrFreq(Param,21,13,5);              (* VFO B *)
        PrCTCSS(Param,25,39,5);
        PrMode(Param,26,31,5);
        PrFreq(Param,9,13,7);               (* Clarifier *)
        PrCTCSS(Param,13,39,7);
        PrMode(Param,14,31,7);
    END; (* IF LENGTH *)
    (* UPPER RIGHT QUADRANT *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(DBG);                     (* Parameter screen colors *)
    GOTOXY(56,1); WRITE('Operating Frequency');
    TEXTCOLOR(DFG);                          (* Display headings *)
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    PrBox;                                   (* Draw `Op Freq' box *)
    GOTOXY(53,5);
    FOR Index := 1 to 7 DO
        WRITE(CHR(205));
    WRITE(' Selected ');
    FOR Index := 1 to 8 DO
        WRITE(CHR(205));
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(DBG);                     (* Parameter screen colors *)
    GOTOXY(54,6); WRITE('Mode');
    GOTOXY(63,6); WRITE('Tone');
    GOTOXY(71,6); WRITE('Memory');
    (* Display returned status for Op Freq, selected mode, tone, memory *)
    PrFreq(Param,2,59,3);                    (* Op Freq *)
    IF LENGTH(Update) >= 8 THEN BEGIN
        PrCTCSS(Param,6,60,7);               (* Tone *)
        PrMode(Param,7,55,7);                (* Mode *)
        TEXTCOLOR(SFG);
        TEXTBACKGROUND(DBG);                 (* Returned status colors *)
        GOTOXY(73,7); WRITE('0');            (* Memory *)
        WRITE(Bin2BCDHex(ORD(Param[8])));
        TEXTCOLOR(DFG);
        TEXTBACKGROUND(DBG);                 (* Default screen colors *)
    END; (* IF LENGTH *)
    (* LOWER LEFT QUADRANT *)
    TEXTCOLOR(PFG);                          (* Display headings *)
    TEXTBACKGROUND(DBG);                     (* Parameter screen colors *)
    FOR Index := 0 TO 9 DO BEGIN
        GOTOXY(2,Index + 9); WRITE('Memory 0');
        WRITE(Index);                        (* Display memory number *)
    END; (* FOR Index *)
    (* Display returned status for all memories *)
    IF LENGTH(Update) = 86 THEN BEGIN
        PrFreq(Param,27,13,9);
        PrCTCSS(Param,31,39,9);
        PrMode(Param,32,31,9);
        PrFreq(Param,33,13,10);
        PrCTCSS(Param,37,39,10);
        PrMode(Param,38,31,10);
        PrFreq(Param,39,13,11);
        PrCTCSS(Param,43,39,11);
        PrMode(Param,44,31,11);
        PrFreq(Param,45,13,12);
        PrCTCSS(Param,49,39,12);
        PrMode(Param,50,31,12);
        PrFreq(Param,51,13,13);
        PrCTCSS(Param,55,39,13);
        PrMode(Param,56,31,13);
        PrFreq(Param,57,13,14);
        PrCTCSS(Param,61,39,14);
        PrMode(Param,62,31,14);
        PrFreq(Param,63,13,15);
        PrCTCSS(Param,67,39,15);
        PrMode(Param,68,31,15);
        PrFreq(Param,69,13,16);
        PrCTCSS(Param,73,39,16);
        PrMode(Param,74,31,16);
        PrFreq(Param,75,13,17);
        PrCTCSS(Param,79,39,17);
        PrMode(Param,80,31,17);
        PrFreq(Param,81,13,18);
        PrCTCSS(Param,85,39,18);
        PrMode(Param,86,31,18);
    END; (* IF LENGTH *)
    (* LOWER RIGHT QUADRANT *)
    GOTOXY(54,9); WRITE('Status Byte Information');
    TEXTCOLOR(PFG);                          (* Display headings *)
    TEXTBACKGROUND(DBG);                     (* Parameter screen colors *)
    GOTOXY(53,11); WRITE('PTT:        ');
    GOTOXY(53,12); WRITE('Ham/Gen:    ');
    GOTOXY(53,13); WRITE('Transmit:   ');
    GOTOXY(53,14); WRITE('Split:      ');
    GOTOXY(53,15); WRITE('VFO:        ');
    GOTOXY(53,16); WRITE('Mem Recall: ');
    GOTOXY(53,17); WRITE('Clarifier:  ');
    GOTOXY(53,18); WRITE('Cat System: ');
    PrStatusByte;                            (* Display decoded status byte information *)
END; (* StatusUpdate *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE TurnCatOn; (* Activate Computer Aided Tuning system *)

BEGIN (* TurnCatOn *)
    CAT := TRUE;
    CatSend(CatOn,86);
    ScreenWrite('  CAT is  ON  ',65,4,CLA);
END; (* TurnCatOn *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE TurnCatOff; (* Deactivate Computer Aided Tuning system *)

BEGIN (* TurnCatOff *)
    CAT := FALSE;
    CatSend(CatOff,86);
    ScreenWrite('  CAT is OFF  ',65,4,COA);
END; (* TurnCatOff *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE CheckStatus(Inst : String5);
(* No change to radio, just request current status *)

BEGIN (* CheckStatus *)
    CatSend(Inst,86);
    StatusUpdate(Update);
    Pause;
    PrFKeys;
    MainMenu;
END; (* CheckStatus *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE QuickStat;
(* Do a quick update in upper left box *)

VAR
    ModePos : INTEGER;

BEGIN (* QuickStat *)
    WINDOW(1,1,20,5);
    (* Display upper left box headings *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Parameter screen colors *)
    GOTOXY(3,2); WRITE('Freq:');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    PrFreq(Update,2,8,2);                    (* Operating Freq *)
    (* Display selected Memory/VFO, Mode status in upper left box *)
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    PrFreq(Update,2,8,2);                    (* Operating Freq *)
  {  GOTOXY(3,14);
    IF (ORD(Update[1])) AND ($08) <> 0 THEN BEGIN (* Mask off SPLIT bit *)
        TEXTCOLOR(SFG +16);
        WRITE('s');
    END (* IF *)
    ELSE WRITE(' ');}
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Special param colors *)
    GOTOXY(3,3); WRITE('Active: ');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    GOTOXY(11,3);
    IF (ORD(Update[1])) AND ($20) <> 0 THEN BEGIN (* Mask off MR bit *)
        WRITE('MEMORY ');
        ModePos := ORD(Update[8]) *6 +32;    (* Calc selected MR mode *)
    END (* IF *)
    ELSE IF (ORD(Update[1])) AND ($10) = 0 THEN BEGIN (* Mask off VFO bit *)
        WRITE('VFO A ');
        ModePos := 20;
    END (* ELSE IF *)
    ELSE BEGIN
        WRITE('VFO B ');
        ModePos := 26;
    END; (* ELSE *)
    IF (ORD(Update[1])) AND ($08) <> 0 THEN BEGIN (* Mask off SPLIT bit *)
        TEXTCOLOR(SFG+16);
        WRITE(CHR(18));
    END (* IF *)
    ELSE IF (ORD(Update[1])) AND ($20) = 0 THEN  (* Mask off MR bit *)
        WRITE(' ');
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Special param colors *)
    GOTOXY(3,4); WRITE('Mode:          ');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    PrMode(Update,ModePos,13,4);
    TEXTCOLOR(SFG+16);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    IF (ORD(Update[1])) AND ($40) <> 0 THEN BEGIN (* Mask off Clar bit *)
        WRITE(' ',CHR(29));
    END (* IF *)
    ELSE WRITE('  ');
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
END; (* QuickStat *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE MainFrame (* Put up Main Frame for all screens *);

BEGIN (* MainFrame *)
    CLRSCR;
    PrFrame(1,80,1,24);                      (* Draw main frame *)
    PrFKeys;                                 (* Display Function Key line *)
    PrMessage(Title,2);                      (* Display headings *)
    PrMessage(Credit,3);
    PrMessage('Main Menu',4);
    PrRule;                                  (* Draw inside ruling lines *)
    ScreenWrite(CHR(209),18,1,SBA);          (* Dbl/sing tee, top *)
    PrLines('V',18,0,2,4,SBA,DBG,179);       (* Sing V left side *)
    ScreenWrite(CHR(207),18,5,SBA);          (* Dbl/sing tee, bot *)
    ScreenWrite(CHR(209),63,1,SBA);          (* Dbl/sing tee, top *)
    PrLines('V',63,0,2,4,SBA,DBG,179);       (* Sing V right side *)
    ScreenWrite(CHR(207),63,5,SBA);          (* Dbl/sing tee, bot *)
END; (* MainFrame *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE MainMenu (* Put up Main Menu for selections *);

VAR
    Fk     : BOOLEAN;
    Choice : CHAR;

BEGIN (* MainMenu *)
    TurnCatOff;                              (* Disable CAT between jobs *)
    WINDOW(1,1,80,5);
    PrMessage('                 Main Menu                 ',4);
    {
    (* Display upper left box headings *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Parameter screen colors *)
    GOTOXY(3,2); WRITE('Freq ');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    PrFreq(Update,2,8,2);                    (* Operating Freq *)
    (* Display selected Memory/VFO, Clarifier status in upper left box *)
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    PrFreq(Update,2,8,2);                    (* Operating Freq *)
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Special param colors *)
    GOTOXY(3,3); WRITE('Active: ');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    GOTOXY(11,3);
    IF (ORD(Update[1])) AND ($20) <> 0 THEN  (* Mask off MR bit *)
        WRITE('MEMORY ')
    ELSE WRITE('   VFO ');
    TEXTCOLOR(PFG);
    TEXTBACKGROUND(Blue);                    (* Special param colors *)
    GOTOXY(3,4); WRITE('Clarifier: ');
    TEXTCOLOR(SFG);
    TEXTBACKGROUND(Blue);                    (* Special status colors *)
    GOTOXY(14,4);
    IF (ORD(Update[1])) AND ($40) <> 0 THEN  (* Mask off Clar bit *)
        WRITE(' ON ')
    ELSE WRITE ('OFF ');
    TEXTCOLOR(DFG);
    TEXTBACKGROUND(DBG);                     (* Default screen colors *)
    }
    QuickStat;
    WINDOW(2,6,79,23);
    CLRSCR;
    (* Display Menu selections *)
    TEXTCOLOR(RFG);
    TEXTBACKGROUND(DBG);                     (* Requested parameter colors *)
    GOTOXY(21,2);  WRITE('1    Display radio status screen');
    GOTOXY(21,3);  WRITE('2    Set Operating frequency');
    GOTOXY(21,4);  WRITE('3    Programmed frequency Step DOWN');
    GOTOXY(21,5);  WRITE('4    Programmed frequency Step UP');
    GOTOXY(21,6);  WRITE('5    Select VFO A/B/Memory');
    GOTOXY(21,7);  WRITE('6    Select Memory channel');
    GOTOXY(21,8);  WRITE('7    Set Operating Mode');
    GOTOXY(21,9);  WRITE('8    Select Ham Bands/General Coverage');
    GOTOXY(21,10); WRITE('9    Set CTCSS Tone frequencies');
    GOTOXY(21,11); WRITE('0    Turn off Split, Clarifier, Offset');
    GOTOXY(21,12); WRITE('+    Step UP 10 Hertz in frequency');
    GOTOXY(21,13); WRITE('-    Step DN 10 Hertz in frequency');
    GOTOXY(13,16); WRITE('Choice ' + CHR(16) + (' ') + CHR(17));
    GOTOXY(21,16);
    REPEAT
        InKey(Fk,Choice);                    (* Get Choice from Menu *)
    UNTIL Choice IN [#43..#68];
    TurnCatOn;                               (* Enable CAT for Choice *)
    CASE Choice OF
        #43 : CatSend(Up10Hz,5);             (* Numeric + *)
        #44 : (* Constant not used - no action *);
        #45 : CatSend(Dn10Hz,5);             (* Numeric - *)
        #46 : (* Constant not used - no action *);
        #47 : (* Constant not used - no action *);
        #48 : CatSend(Aclr,26);              (* Numeric 0 *)
        #49 : CheckStatus(Check);            (* Numeric 1 *)
        #50 : SetFreq;                       (* Numeric 2 *)
        #51 : BEGIN
                  DownFlag := TRUE;
                  ProgStep;                  (* Numeric 3 *)
              END;
        #52 : BEGIN
                  DownFlag := FALSE;
                  ProgStep;                  (* Numeric 4 *)
              END;
        #53 : VFOMRSelect;                   (* Numeric 5 *)
        #54 : MemSelect;                     (* Numeric 6 *)
        #55 : ModeSelect;                    (* Numeric 7 *)
        #56 : HGSelect;                      (* Numeric 8 *)
        #57 : CTCSSToneSet;                  (* Numeric 9 *)
        #58 : (* Constant not used - no action *);
        #59 : SelectMemFile;                 (* Fk 1 *)
        #60 : SelectVFOFile;                 (* Fk 2 *)
        #61 : CatSend(BandDn,5);             (* Fk 3 *)
        #62 : CatSend(BandUp,5);             (* Fk 4 *)
        #63 : CatSend(SplitTog,26);          (* Fk 5 *)
        #64 : CatSend(ClarTog,26);           (* Fk 6 *)
        #65 : BEGIN
                  CatSend(MToV,26);          (* Fk 7 *)
                  CatSend(Nul3String+CHR(0)+CHR(9),5);
              END;
        #66 : BEGIN
                  CatSend(VToM,26);          (* Fk 8 *)
                  CatSend(Nul3String+CHR(2)+CHR(9),5);
              END;
        #67 : CatSend(Swap,5);               (* Fk 9 *)
        #68 : QuitFlag := TRUE;              (* Fk 10 quits the program *)
    END; (* CASE *)
END; (* MainMenu *)

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
FUNCTION Offset(Page,BarPos : INTEGER) : STRING;
(* Compute repeater Split from operating frequency, return Offset Freq *)

VAR
    FreqSet,
    FreqInt,
    LSDFreq,
    Junk,
    FreqString : STRING[8];
    Ofs        : CHAR;
    DotPos,
    Result     : INTEGER;
    FreqTune   : REAL;

BEGIN (* Offset *)
    LSDFreq    := '';
    FreqInt    := '';
    FreqString := '';
    Ofs        := ' ';
    (* Get repeater's OUTPUT Frequency from Memory array *)
    VAL(COPY(MemArray[Page *10 +BarPos],1,8),FreqTune,Result);
    FreqTune := FreqTune;
    Ofs := MemArray[Page *10 +BarPos,23];
    (* 6 meter repeaters *)
    IF FreqTune < 14400000 THEN BEGIN
        IF Ofs = '-' THEN FreqTune := FreqTune - 100000;
        IF Ofs = '+' THEN FreqTune := FreqTune + 100000;
    END; (* IF *)
    (* 2 meter repeaters *)
    IF (FreqTune >= 14400000) AND (FreqTune <= 14800000) THEN BEGIN
        IF Ofs = '-' THEN FreqTune := FreqTune - 60000;
        IF Ofs = '+' THEN FreqTune := FreqTune + 60000;
    END; (* IF *)
    (* 70 centimeter repeaters *)
    IF (FreqTune >= 42000000) AND (FreqTune <= 45000000) THEN BEGIN
        IF Ofs = '-' THEN FreqTune := FreqTune - 500000;
        IF Ofs = '+' THEN FreqTune := FreqTune + 500000;
    END; (* IF *)
    (* Construct LSD->MSD string for Offset value *)
    STR(FreqTune:8:0,FreqString);
    WHILE COPY(FreqString,1,1) = ' ' DO
        DELETE(FreqString,1,1);
    FreqInt := MultString(8 - LENGTH(FreqString),'0') +FreqString;
    LSDFreq := MakeLSDMSD(FreqInt,8);
    Offset  := FreqParm(LSDFreq,8);
END; (* Offset *)

END. (* of UNIT Y767INST *)
