home *** CD-ROM | disk | FTP | other *** search
- { global declarations }
-
- const
- UART_THR = $00; { offset from base of UART Registers for IBM PC }
- UART_RBR = $00;
- UART_IER = $01;
- UART_IIR = $02;
- UART_LCR = $03;
- UART_MCR = $04;
- UART_LSR = $05;
- UART_MSR = $06;
-
- I8088_IMR = $21; { port address of the Interrupt Mask Register }
-
- COM1_Base = $03F8; { port addresses for the UART }
- COM2_Base = $02F8;
-
- COM1_Irq = 4; { Interrupt line for the UART }
- COM2_Irq = 3;
-
- Async_Buffer_Max = $0FFF;
-
- var
-
- OldInterruptSegment,
- OldInterruptOffset : integer;
-
- Async_Buffer : Array[0..Async_Buffer_Max] of char;
- Async_Open_Flag : Boolean; { true if Open but no Close }
- Async_Port : Integer; { current Open port number (1 or 2) }
- Async_Base : Integer; { base for current open port }
- Async_Irq : Integer; { irq for current open port }
-
- Async_Buffer_Overflow : Boolean; { True if buffer overflow has happened }
- Async_Buffer_Used : Integer;
- Async_MaxBufferUsed : Integer;
-
- { Async_Buffer is empty if Head = Tail }
- Async_Buffer_Head : Integer; { Locn in Async_Buffer to put next char }
- Async_Buffer_Tail : Integer; { Locn in Async_Buffer to get next char }
- Async_Buffer_NewTail : Integer;
-
- const
- Async_Num_Bauds = 8;
- Async_Baud_Table : array [1..Async_Num_Bauds] of record
- Baud, Bits : integer
- end
- = ((Baud:110; Bits:$00),
- (Baud:150; Bits:$20),
- (Baud:300; Bits:$40),
- (Baud:600; Bits:$60),
- (Baud:1200; Bits:$80),
- (Baud:2400; Bits:$A0),
- (Baud:4800; Bits:$C0),
- (Baud:9600; Bits:$E0));
-
- {----------------------------------------------------------------------}
- { Issue Interrupt $14 to initialize the UART }
- { See the IBM PC Technical Reference Manual for the format of ComParm }
- {----------------------------------------------------------------------}
-
- procedure BIOS_RS232_Init(ComPort, ComParm : Integer);
- var
- Regs : Registers;
- begin
- with Regs do
- begin
- ax := ComParm AND $00FF; { AH=0; AL=ComParm }
- dx := ComPort;
- Intr($14, Regs)
- end
- end; { BIOS_RS232_Init }
-
- {----------------------------------------------------------------------}
- { call DOS to set an interrupt vector }
- {----------------------------------------------------------------------}
- procedure GetInterruptVector(v : integer);
- var Regs : Registers;
- begin
- with Regs do
- begin
- ax := $3500 + (v AND $00FF);
- MsDos(Regs);
- OldInterruptSegment := bx;
- OldInterruptOffset := es;
- end;
- end;
-
- procedure DOS_Set_Intrpt(v, s, o : integer);
- var
- Regs : Registers;
- begin
- with Regs do
- begin
- ax := $2500 + (v AND $00FF);
- ds := s;
- dx := o;
- MsDos(Regs)
- end
- end; { DOS_Set_Intrpt }
-
- procedure RestoreInterruptVector(v : integer);
- begin
- DOS_Set_Intrpt(v, OldInterruptSegment, OldInterruptOffset);
- end;
-
- {----------------------------------------------------------------------}
- { }
- { ASYNCISR.INC - Interrupt Service Routine }
- { Invoked when the UART has received a byte of data from the }
- { communication line }
- { }
- {----------------------------------------------------------------------}
-
- procedure Async_Isr;
- interrupt;
- begin
-
- Inline(
- $FB/ { STI }
- { get the incoming character }
- { Async_Buffer[Async_Buffer_Head] := Chr(Port[UART_RBR + Async_Base]); }
- $8B/$16/Async_Base/ { MOV DX,Async_Base }
- $EC/ { IN AL,DX }
- $8B/$1E/Async_Buffer_Head/ { MOV BX,Async_Buffer_Head }
- $88/$87/Async_Buffer/ { MOV Async_Buffer[BX],AL }
- { Async_Buffer_NewHead := Async_Buffer_Head + 1; }
- $43/ { INC BX }
- { if Async_Buffer_NewHead > Async_Buffer_Max then
- Async_Buffer_NewHead := 0; }
- $81/$FB/Async_Buffer_Max/ { CMP BX,Async_Buffer_Max }
- $7E/$02/ { JLE L001 }
- $33/$DB/ { XOR BX,BX }
- { if Async_Buffer_NewHead = Async_Buffer_Tail then
- Async_Buffer_Overflow := TRUE
- else }
- {L001:}
- $3B/$1E/Async_Buffer_Tail/ { CMP BX,Async_Buffer_Tail }
- $75/$08/ { JNE L002 }
- $C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 }
- $90/ { NOP generated by assembler for some reason }
- $EB/$16/ { JMP SHORT L003 }
- { begin
- Async_Buffer_Head := Async_Buffer_NewHead;
- Async_Buffer_Used := Async_Buffer_Used + 1;
- if Async_Buffer_Used > Async_MaxBufferUsed then
- Async_MaxBufferUsed := Async_Buffer_Used
- end; }
- {L002:}
- $89/$1E/Async_Buffer_Head/ { MOV Async_Buffer_Head,BX }
- $FF/$06/Async_Buffer_Used/ { INC Async_Buffer_Used }
- $8B/$1E/Async_Buffer_Used/ { MOV BX,Async_Buffer_Used }
- $3B/$1E/Async_MaxBufferUsed/ { CMP BX,Async_MaxBufferUsed }
- $7E/$04/ { JLE L003 }
- $89/$1E/Async_MaxBufferUsed/ { MOV Async_MaxBufferUsed,BX }
- {L003:}
- { disable interrupts }
- $FA/ { CLI }
- { Port[$20] := $20; } { use non-specific EOI }
- $B0/$20/ { MOV AL,20h }
- $E6/$20 ) { OUT 20h,AL }
- end; { Async_Isr }
-
- {----------------------------------------------------------------------}
- { Async_Init }
- { Performs initialization. }
- {----------------------------------------------------------------------}
-
- procedure Async_Init;
- begin
- Async_Open_Flag := FALSE;
- Async_Buffer_Overflow := FALSE;
- Async_Buffer_Used := 0;
- Async_MaxBufferUsed := 0;
- end; { Async_Init }
-
- {----------------------------------------------------------------------}
- { Async_Close }
- { Turn off the COM port interrupts. }
- { reset the interrupt system when UART interrupts no longer needed }
- {----------------------------------------------------------------------}
-
- procedure Async_Close;
- var
- i, m : Integer;
- begin
- if Async_Open_Flag then { disable the IRQ on the 8259 }
- begin
- Inline($FA); { disable interrupts }
- i := Port[I8088_IMR]; { get the interrupt mask register }
- m := 1 shl Async_Irq; { set mask to turn off interrupt }
- Port[I8088_IMR] := i OR m;
- { disable the 8250 data ready interrupt }
- Port[UART_IER + Async_Base] := 0;
- { disable OUT2 on the 8250 }
- Port[UART_MCR + Async_Base] := 0;
- Inline($FB); { enable interrupts }
- { restore old interrupt vector }
- RestoreInterruptVector(Async_Irq + 8);
- Async_Open_Flag := FALSE { so we know the port is closed }
- end
- end; { Async_Close }
-
- {----------------------------------------------------------------------}
- { Async_Open(Port, Baud : Integer; }
- { Parity : Char; }
- { WordSize, StpBits : Integer) : Boolean }
- { Sets up interrupt vector, initialies the COM port for }
- { processing, sets pointers to the buffer. Returns FALSE if COM }
- { port not installed. }
- {----------------------------------------------------------------------}
-
- function Async_Open(ComPort : Integer;
- BaudRate : Integer;
- Parity : Char;
- WordSize : Integer;
- StopBits : Integer): boolean;
- var
- ComParm : Integer;
- i, m : Integer;
- begin
- if Async_Open_Flag then Async_Close;
-
- if ComPort = 2 then
- begin
- Async_Port := 2;
- Async_Base := COM2_Base;
- Async_Irq := COM2_Irq
- end
- else
- begin
- Async_Port := 1; { default to COM1 }
- Async_Base := COM1_Base;
- Async_Irq := COM1_Irq
- end;
-
- GetInterruptVector(Async_Irq + 8);
-
- if (Port[UART_IIR + Async_Base] AND $00F8) <> 0
- then
- Async_Open := FALSE
- else
- begin
-
- Async_Buffer_Head := 0;
- Async_Buffer_Tail := 0;
- Async_Buffer_Overflow := FALSE;
-
- { Build the ComParm for RS232_Init }
- { See Technical Reference Manual for description }
-
- ComParm := $0000;
-
- { Set up the bits for the baud rate }
- i := 0;
- repeat
- i := i + 1
- until (Async_Baud_Table[i].Baud = BaudRate) OR (i = Async_Num_Bauds);
- ComParm := ComParm OR Async_Baud_Table[i].Bits;
-
- if Parity in ['E', 'e'] then ComParm := ComParm OR $0018
- else if Parity in ['O', 'o'] then ComParm := ComParm OR $0008
- else ComParm := ComParm OR $0000; { default to No parity }
-
- if WordSize = 7
- then ComParm := ComParm OR $0002
- else ComParm := ComParm OR $0003; { default to 8 data bits }
-
- if StopBits = 2
- then ComParm := ComParm OR $0004
- else ComParm := ComParm OR $0000; { default to 1 stop bit }
-
- { use the BIOS COM port initialization routine to save typing the code }
- BIOS_RS232_Init(Async_Port - 1, ComParm);
-
- DOS_Set_Intrpt(Async_Irq + 8, CSeg, Ofs(Async_Isr));
-
- { read the RBR and reset any possible pending error conditions }
- { first turn off the Divisor Access Latch Bit to allow access to RBR, etc. }
-
- Inline($FA); { disable interrupts }
-
- Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] AND $7F;
- { read the Line Status Register to reset any errors it indicates }
- i := Port[UART_LSR + Async_Base];
- { read the Receiver Buffer Register in case it contains a character }
- i := Port[UART_RBR + Async_Base];
-
- { enable the irq on the 8259 controller }
- i := Port[I8088_IMR]; { get the interrupt mask register }
- m := (1 shl Async_Irq) XOR $00FF;
- Port[I8088_IMR] := i AND m;
-
- { enable the data ready interrupt on the 8250 }
- Port[UART_IER + Async_Base] := $01; { enable data ready interrupt }
-
- { enable OUT2 on 8250 }
- i := Port[UART_MCR + Async_Base];
- Port[UART_MCR + Async_Base] := i OR $08;
-
- Inline($FB); { enable interrupts }
- Async_Open_Flag := TRUE; { bug fix by Scott Herr }
- Async_Open := TRUE;
- end;
- end; { Async_Open }
-
- {----------------------------------------------------------------------}
- { Transmits the character. }
- {----------------------------------------------------------------------}
-
- procedure kam_out(C : char);
- var
- i, m, counter : Integer;
- begin
- Port[UART_MCR + Async_Base] := $0B; { turn on OUT2, DTR, and RTS }
-
- { wait for CTS }
- counter := MaxInt;
- while (counter <> 0) AND ((Port[UART_MSR + Async_Base] AND $10) = 0) do
- counter := counter - 1;
-
- { wait for Transmit Hold Register Empty (THRE) }
- if counter <> 0 then counter := MaxInt;
- while (counter <> 0) AND ((Port[UART_LSR + Async_Base] AND $20) = 0) do
- counter := counter - 1;
-
- if counter <> 0 then
- begin
- { send the character }
- Inline($FA); { disable interrupts }
- Port[UART_THR + Async_Base] := Ord(C);
- Inline($FB) { enable interrupts }
- end
- else
- begin
- Async_close;
- restore_entry_screen;
- writeln('COM',xmt_port:1,' has timed out.');
- writeln('Check KAM for power on and/or proper operation.');
- halt;
- end;
- end;
-
- {----------------------------------------------------------------------}
- { Remove Character From Interrupt Driven Buffer }
- {----------------------------------------------------------------------}
-
- function kam_in: char;
- begin
- Inline($FA); { disable interrupts }
- kam_in := Async_Buffer[Async_Buffer_Tail];
- Async_Buffer_Tail := (Async_Buffer_Tail + 1) AND Async_Buffer_Max;
- Async_Buffer_Used := Async_Buffer_Used - 1;
- Inline($FB); { enable interrupts }
- end;
-
- {----------------------------------------------------------------------}
- { If a character is available, returns TRUE }
- {----------------------------------------------------------------------}
-
- function char_ready:boolean;
- begin
- char_ready := (Async_Buffer_Head <> Async_Buffer_Tail);
- { if (Async_Buffer_Head = Async_Buffer_Tail)
- then char_ready := FALSE
- else char_ready := TRUE; }
- end;
-
- var _bufchr : char;
-
- procedure clear_buffer;
- begin
- repeat
- if char_ready then _bufchr := kam_in;
- delay(10);
- until NOT char_ready;
- end;
-
- procedure kam_cmd(s : msg_type);
- var i : integer;
- begin
- for i := 1 to length(s) do
- kam_out(s[i]);
- end;
-
- procedure kam_cmd_CR(s : msg_type);
- begin
- kam_cmd(s + #13);
- end;
-
- procedure xmt_mode;
- begin
- if mode in [CW,RTTY,ASCII] then
- begin
- xmt_ON := TRUE;
- kam_cmd(^C'T');
- clear_buffer;
- case mode of
- CW : ;
- RTTY, ASCII : if xmt_on_delay > 0 then
- delay(xmt_on_delay * 100);
- end;
- end;
- end;
-
- procedure cw_status;
- var status_str : string[7];
- i : integer;
- begin
- status_str := ' ';
- repeat
- for i := 1 to 6 do
- status_str[i] := status_str[i + 1];
- repeat until char_ready;
- status_str[7] := kam_in;
- until (status_str[1] = '-');
- if (status_str[7] = '-') then
- rcv_wpm := copy(status_str,5,2);
- end;
-
- procedure rcv_stat;
- begin
- if mode in [CW,RTTY,ASCII] then
- begin
- kam_cmd(^C'R');
- case mode of
- ASCII : clear_buffer;
- RTTY : clear_buffer;
- CW : cw_status;
- end;
- end;
- end;
-
- procedure rcv_mode;
- begin
- if mode in [CW,RTTY,ASCII] then
- begin
- xmt_ON := FALSE;
- rcv_stat;
- end;
- end;
-
-
- procedure set_rtty_baud;
- begin
- kam_cmd(^C'R');
- kam_cmd(^C + chr(49+baud));
- clear_buffer;
- if xmt_ON then xmt_mode;
- end;
-
- procedure mod_rtty_invert;
- begin
- kam_cmd(^C'R');
- kam_cmd(^C'I');
- invert := NOT invert;
- clear_buffer;
- if xmt_ON then xmt_mode;
- end;
-
- procedure set_rtty_shift;
- begin
- kam_cmd(^C'R');
- kam_cmd(^C'S');
- clear_buffer;
- if xmt_on then xmt_mode;
- end;
-
- procedure cw_mode;
- begin
- mode := CW;
- kam_cmd_CR('E OFF');
- kam_cmd_CR('XM ON');
- clear_buffer;
- kam_cmd_CR('CW ' + xmt_wpm);
- cw_status;
- state := receive;
- end;
-
- procedure kam_xmt_wpm;
- begin
- kam_cmd(^C'X');
- clear_buffer;
- cw_mode;
- if xmt_ON then
- kam_cmd(^C'T');
- end;
-
- procedure rtty_mode;
- begin
- baud := 0;
- mode := RTTY;
- kam_cmd_CR('E OFF');
- kam_cmd_CR('XM ON');
- kam_cmd_CR('MARK 2100');
- kam_cmd_CR('SPACE 2300');
- kam_cmd_CR('RB ' + baud_rate[baud] );
- kam_cmd_CR('SH ' + rtty_shift[shift]);
- kam_cmd_CR('INVERT OFF');
- kam_cmd_CR('CRAdd ON');
- kam_cmd_CR('LF ON');
- kam_cmd_CR('DIDdle ON');
- kam_cmd_CR('R');
- state := receive;
- end;
-
- procedure ascii_mode;
- begin
- baud := 5;
- mode := ASCII;
- kam_cmd_CR('MARK 2100');
- kam_cmd_CR('SPACE 2300');
- kam_cmd_CR('ASCB ' + baud_rate[baud] );
- kam_cmd_CR('INVERT OFF');
- kam_cmd_CR('CRAdd ON');
- kam_cmd_CR('LF ON');
- kam_cmd_CR('A');
- state := receive;
- end;
-
- procedure packet_mode;
- begin
- mode := PACKET;
- kam_cmd_CR('MARK '+packet_mark);
- kam_cmd_CR('SPACE '+packet_space);
- kam_cmd_CR('E ON');
- kam_cmd_CR(SW_VHF+'A');
- band := VHF;
- state := transceive;
- end;
-
- procedure HF_Packet;
- begin
- kam_cmd(^C);
- kam_cmd_CR(SW_HF+'A');
- band := HF;
- end;
-
- procedure VHF_Packet;
- begin
- kam_cmd(^C);
- kam_cmd_CR(SW_VHF+'A');
- band := VHF;
- end;
-
- procedure amtor_mode;
- begin
- mode := AMTOR;
- state := transceive;
- kam_cmd_CR('E ON');
- kam_cmd_CR('A');
- band := HF;
- end;
-
- procedure packet_connect;
- begin
- kam_cmd_CR('C ' + PKCall);
- end;
-
- procedure packet_disconnect;
- begin
- kam_cmd(^C);
- kam_cmd_CR('D');
- end;
-
- procedure PacketID;
- var i : integer;
- begin
- kam_cmd_CR(^C);
- clear_buffer;
- for i := 1 to 5 do
- begin
- kam_cmd_CR('I');
- delay(2000);
- end;
- clear_buffer;
- end;
-
-
- procedure new_mode;
- begin
- clear_buffer;
- case mode of
- AMTOR, CW, RTTY, ASCII : kam_cmd(^C'X');
- PACKET : kam_cmd_CR(^C'D');
- end;
- clear_buffer;
- save_screen;
- aux_color;
- window(35,8,45,16);
- clrscr;
- writeln;
- writeln(' 1> CW');
- writeln(' 2> RTTY');
- writeln(' 3> ASCII');
- writeln(' 4> PACKET');
- writeln(' 5> AMTOR');
- writeln;
- write (' select..');
- repeat key := readkey until key in ['1'..'5'];
- case key of
- '1' : cw_mode;
- '2' : rtty_mode;
- '3' : ascii_mode;
- '4' : packet_mode;
- '5' : amtor_mode;
- end;
- window(1,1,80,25);
- restore_screen;
- end;
-
- procedure init_interface;
- begin
- Async_Init;
- if (Async_Open(xmt_port, kam_baud_rate, 'N', 8, 1) = FALSE) then
- begin
- restore_entry_screen;
- Writeln('COM',xmt_port:1,' not installed.');
- halt;
- end;
- writeln('Initializing KAM interface');
- kam_cmd_CR('XOFF 0');
- kam_cmd_CR('XON 0'); clear_buffer;
- packet_mode;
- end;
-
- procedure reset_kam;
- begin
- case mode of
- CW, RTTY, ASCII, AMTOR : kam_cmd(^C'X');
- PACKET : begin
- kam_cmd_CR('MARK 2100');
- kam_cmd_CR('SPACE 2300');
- kam_cmd_CR(SW_VHF+'A');
- end;
- end;
- clear_buffer;
- Async_close;
- end;
-