with Interrupt; with CharAK; -- for Demo with Cursor; -- for Demo with ErroAKD; with IntrAKD; with PortAKD; with ScrnAKD; with TextAKD; -- for Pause substitutes with System ; -- for Demo package body CommAKD is --------------------------------------------------------------------------- --------------------------------------------------------------------------- function Data_Is_Ready ( Status: in integer ) return boolean is --------------------------------------------------------------------------- begin return Bits_Are_Set ( Status, Bit8_Word ); end Data_Is_Ready; procedure Demo is ---------------------------------------------------------------------- Com_Index : array ( CommAKD.Com1..CommAKD.Com2 ) of integer := ( 1, 1 ); Com_Index_Max: constant integer := 80; Com_Input : array ( CommAKD.Com1..CommAKD.Com2 ) of string ( 1..Com_Index_Max ); task Testing is pragma priority (3); entry Entry_Com1; entry Entry_Com2; for Entry_Com1 use at IntrAKD.Int_Com1; for Entry_Com2 use at IntrAKD.Int_Com2; end Testing; task Enable_Ints_When_Ready is pragma priority (2); entry Enable ( Port: in CommAKD.Port_Type ); end Enable_Ints_When_Ready; task Display is pragma priority (1); end; procedure Read_Port ( Port: in CommAKD.Port_Type ) is --------------------------------------------------------------------------- -- Reads character and puts it in Com_Input(Port) then enables interrupts. --------------------------------------------------------------------------- begin if Com_Index ( Port ) = Com_Index_Max then Com_Index ( Port ) := 1; else Com_Index ( Port ) := Com_Index ( Port ) + 1; end if; Com_Input ( Port ) ( Com_Index ( Port ) ) := CharAK.Filter ( character'val ( Clear_Bits ( CommAKD.Get_RDR ( Port ), Bit7_Byte ) ) ); Enable_Ints_When_Ready.Enable ( Port ); end Read_Port; task body Testing is --------------------------------------------------------------------------- begin loop select accept Entry_Com1 do Read_Port ( CommAKD.Com1 ); end Entry_Com1; or accept Entry_Com2 do Read_Port ( CommAKD.Com2 ); end Entry_Com2; end select; end loop; end Testing; task body Enable_Ints_When_Ready is --------------------------------------------------------------------------- PIC_Level: IntrAKD.PIC_Level_Type; begin loop accept Enable ( Port: in CommAKD.Port_Type ) do case Port is when CommAKD.Com1 => PIC_Level := IntrAKD.PIC_Com1; when CommAKD.Com2 => PIC_Level := IntrAKD.PIC_Com2; when CommAKD.Com3 => PIC_Level := IntrAKD.PIC_Com3; when CommAKD.Com4 => PIC_Level := IntrAKD.PIC_Com4; end case; end Enable; IntrAKD.PIC_8259_EOI ( PIC_Level ); end loop; end Enable_Ints_When_Ready; task body Display is --------------------------------------------------------------------------- begin loop -- CommAKD.Setup ( Port => CommAKD.Com1, BPS => 9600 ); CommAKD.Setup ( Port => CommAKD.Com2, BPS => 1200 ); -- CommAKD.Interrupt_Handling ( CommAKD.Com1, true ); CommAKD.Interrupt_Handling ( CommAKD.Com2, true ); ScrnAKD.ClrScr; for index in 1..99 loop Cursor.Move ( 0, 0 ); -- CommAKD.Registers_Display ( CommAKD.Registers_Fetch ( CommAKD.Com1)); CommAKD.Registers_Display ( CommAKD.Registers_Fetch ( CommAKD.Com2)); ---- IntrAKD.PIC_8259_Show; -- ScrnAKD.Put ( Com_Input ( CommAKD.Com1 ) -- ( Com_Index ( CommAKD.Com1 ) ) & " " ); -- ScrnAKD.Put_Line ( "Com_Index ( Com1 ): " -- & integer'image ( Com_Index ( CommAKD.Com1 ) ) ); ScrnAKD.Put ( Com_Input ( CommAKD.Com2 ) ( Com_Index ( CommAKD.Com2 ) ) & " " ); ScrnAKD.Put_Line ( "Com_Index ( Com2 ): " & integer'image ( Com_Index ( CommAKD.Com2 ) ) ); end loop; -- IntrAKD.PIC_8259_EOI ( IntrAKD.PIC_Com1 ); IntrAKD.PIC_8259_EOI ( IntrAKD.PIC_Com2 ); -- CommAKD.Interrupt_Handling ( CommAKD.Com1, false ); CommAKD.Interrupt_Handling ( CommAKD.Com2, false ); declare Dum_Str : string ( 1..10 ); Dum_Last : natural; begin TextAKD.Put ( "Please press ENTER to continue..." ); TextAKD.Get_Line ( Dum_Str, Dum_Last ); end; end loop; exception when others => ErroAKD.Notify ( "Display" ); ScrnAKD.Put ( "Aborting..." ); CommAKD.Interrupt_Handling ( CommAKD.Com1, false ); CommAKD.Interrupt_Handling ( CommAKD.Com2, false ); abort Testing; abort Enable_Ints_When_Ready; ScrnAKD.Put_Line ( "done." ); end Display; ---------------------------------------------------------------------- ---------------------------------------------------------------------- begin null; end Demo; function Get_IIR ( Port: in Port_Type ) return Byte_Type is --------------------------------------------------------------------------- begin return PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( IIR ) ); end Get_IIR; function Get_LSR ( Port: in Port_Type ) return Byte_Type is --------------------------------------------------------------------------- begin return PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LSR ) ); end Get_LSR; function Get_MCR ( Port: in Port_Type ) return MCR_Record_Type is --------------------------------------------------------------------------- MCReg: Byte_Type; MCRec: MCR_Record_Type; begin MCReg := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( MCR ) ); MCRec.DTR_Active := Bits_Are_Set ( MCReg, Bit0_Byte ); MCRec.RTS_Active := Bits_Are_Set ( MCReg, Bit1_Byte ); MCRec.Hayes_Reset := Bits_Are_Set ( MCReg, Bit2_Byte ); MCRec.Enable_Ints := Bits_Are_Set ( MCReg, Bit3_Byte ); MCRec.UART_Loopback := Bits_Are_Set ( MCReg, Bit4_Byte ); return MCRec; end Get_MCR; function Get_MCR ( Port: in Port_Type ) return Byte_Type is --------------------------------------------------------------------------- begin return PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( MCR ) ); end Get_MCR; function Get_MSR ( Port: in Port_Type ) return Byte_Type is --------------------------------------------------------------------------- begin return PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( MSR ) ); end Get_MSR; function Get_RDR ( Port: in Port_Type ) return Byte_Type is --------------------------------------------------------------------------- LCReg, RDReg: Byte_Type; begin LCReg := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ) ); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Clear_Bits ( LCReg, Bit7_Byte ) ); RDReg := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( THR_RDR ) ); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), LCReg ); return RDReg; end Get_RDR; procedure Interrupt_Handling ( Port: in Port_Type; On: in boolean ) is --------------------------------------------------------------------------- -- Be sure to turn interrupt handling off before your program finishes. -- This only enables Data Received interrupts. --------------------------------------------------------------------------- MCR_Rec: MCR_Record_Type; PIC_Level: IntrAKD.PIC_Level_Type; begin case Port is when Com1 => PIC_Level := IntrAKD.PIC_Com1; when Com2 => PIC_Level := IntrAKD.PIC_Com2; when Com3 => PIC_Level := IntrAKD.PIC_Com1; when Com4 => PIC_Level := IntrAKD.PIC_Com2; end case; if On then IntrAKD.PIC_8259 ( PIC_Level, true ); Set_IER ( Port, true , false, false, false ); MCR_Rec := Get_MCR ( Port ); MCR_Rec.Enable_Ints := true; Set_MCR ( Port, MCR_Rec ); else IntrAKD.PIC_8259 ( PIC_Level, false ); Set_IER ( Port, false, false, false, false ); MCR_Rec := Get_MCR ( Port ); MCR_Rec.Enable_Ints := false; Set_MCR ( Port, MCR_Rec ); end if; end Interrupt_Handling; procedure Read_Char ( Port: in Port_Type; Is_Found: out boolean; C: out character ) is --------------------------------------------------------------------------- -- Note: Interrupt 14h, Function 02h is too slow for more than 300 Baud. --------------------------------------------------------------------------- R: Interrupt.Registers; begin R.AX := integer ( Set_Byte ( R.AX, 16#02#, false ) ); R.DX := Port_Type'pos ( Port ); Interrupt.Vector ( 16#14#, R ); Is_Found := not ( Bits_Are_Set ( Bit15_Word, R.AX ) ); C := character'val ( Get_Byte ( R.AX, true ) ); end Read_Char; procedure Registers_Display ( Registers: in Registers_Type ) is --------------------------------------------------------------------------- use ScrnAKD; begin Put_Line ( "8250 Registers" ); Put_Line; Put_Line ( "Receiver data register..............RDR: " & Byte_Type'image ( Registers.THR_RDR ) & " " ); Put_Line ( "Baud rate divisor, low byte........BRDL: " & Byte_Type'image ( Registers.BRDL ) & ' ' ); Put_Line ( "Interrupt enable register...........IER: " & Byte_Type'image ( Registers.IER ) & ' ' ); Put_Line ( "Baud rate divisor, high byte.......BRDH: " & Byte_Type'image ( Registers.BRDH ) & ' ' ); Put_Line ( "Interrupt identification register...IIR: " & Byte_Type'image ( Registers.IIR ) & ' ' ); Put_Line ( "Line control register...............LCR: " & Byte_Type'image ( Registers.LCR ) & ' '); Put_Line ( "Modem control register..............MCR: " & Byte_Type'image ( Registers.MCR ) & ' '); Put_Line ( "Line status register................LSR: " & Byte_Type'image ( Registers.LSR ) & ' '); Put_Line ( "Modem status register...............MSR: " & Byte_Type'image ( Registers.MSR ) & ' '); end Registers_Display; function Registers_Fetch ( Port: in Port_Type ) return Registers_Type is --------------------------------------------------------------------------- R: Registers_Type; begin R.LCR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ) ); -- Clear LCR Bit7 and read RDR and IER. PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Clear_Bits ( R.LCR, Bit7_Byte ) ); R.THR_RDR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( THR_RDR ) ); R.IER := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( IER ) ); -- Set LCR Bit7 and read BRDL and BRDH. PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Set_Bits ( R.LCR, Bit7_Byte ) ); R.BRDL := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( BRDL ) ); R.BRDH := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( BRDH ) ); -- Restore original LCR. PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), R.LCR ); R.IIR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( IIR ) ); R.MCR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( MCR ) ); R.LSR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LSR ) ); R.MSR := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( MSR ) ); return R; end Registers_Fetch; function Send ( Port: in Port_Type; C: in Byte_Type ) return boolean is --------------------------------------------------------------------------- THR_Is_Empty: boolean := false; begin for index in 1..1000 loop THR_Is_Empty := Bits_Are_Set ( Get_LSR ( Port ), Bit5_Byte); exit when THR_Is_Empty; end loop; PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( THR_RDR ), C ); return THR_Is_Empty; end Send; procedure Set_BPS ( Port: in Port_Type; BPS: in BPS_Type ) is --------------------------------------------------------------------------- Bit7_Was_Set: boolean; BRD: Word_Type; -- Baud Rate Divisor LCReg: Byte_Type; -- Line Control Register begin BRD := Word_Type ( BPS_Type'last / BPS ); -- Read original LCR LCReg := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ) ); -- Store entry LCR Bit7_Byte status Bit7_Was_Set := Bits_Are_Set ( LCReg, Bit7_Byte ); -- Set LCR Bit7 PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Set_Bits ( LCReg, Bit7_Byte ) ); -- Write to BRDH and BRDL PortAKD.Out_Word ( Port_Base_Address ( Port ) + Offset ( BRDL ), BRD ); -- Restore original LCR Bit7 if not ( Bit7_Was_Set ) then PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Clear_Bits ( LCReg, Bit7_Byte ) ); end if; end Set_BPS; procedure Set_IER ( Port: in Port_Type; IE_Data_Received: in boolean; IE_THR_Empty: in boolean; IE_Data_Error_Break: in boolean; IE_MSR_Change: in boolean ) is --------------------------------------------------------------------------- use BitsAKD; Bit7_Was_Set: boolean; IEReg: Byte_Type := 16#00#; LCReg: Byte_Type; begin -- Read original LCR LCReg := PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ) ); -- Store entry LCR Bit7_Byte status Bit7_Was_Set := Bits_Are_Set ( LCReg, Bit7_Byte ); -- Clear LCR Bit7 PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Clear_Bits ( LCReg, Bit7_Byte ) ); IEReg := Set_Bits ( IEReg, boolean'pos ( IE_Data_Received ) * Bit0_Byte ); IEReg := Set_Bits ( IEReg, boolean'pos ( IE_THR_Empty ) * Bit1_Byte ); IEReg := Set_Bits ( IEReg, boolean'pos ( IE_Data_Error_Break ) * Bit2_Byte ); IEReg := Set_Bits ( IEReg, boolean'pos ( IE_MSR_Change ) * Bit3_Byte ); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( IER ), IEReg ); -- Restore original LCR Bit7 if Bit7_Was_Set then PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), Set_Bits ( LCReg, Bit7_Byte ) ); end if; end Set_IER; procedure Set_LCR ( Port: in Port_Type; Char_Length: in Char_Length_Type; Stop_Bits: in Stop_Bits_Type; Parity: in Parity_Type_2; Break_Enabled: in boolean; Port_Alternate: in boolean ) is --------------------------------------------------------------------------- use BitsAKD; LCReg: Byte_Type := 16#00#; begin LCReg := Set_Bits ( LCReg, Char_Length_Type'pos ( Char_Length )*Bit0_Byte); LCReg := Set_Bits ( LCReg, Stop_Bits_Type 'pos ( Stop_Bits )*Bit2_Byte); LCReg := Set_Bits ( LCReg, Parity_Type_2 'pos ( Parity )*Bit3_Byte); LCReg := Set_Bits ( LCReg, boolean 'pos ( Break_Enabled )*Bit6_Byte); LCReg := Set_Bits ( LCReg, boolean 'pos ( Port_Alternate )*Bit7_Byte); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ), LCReg ); end Set_LCR; procedure Set_MCR ( Port: in Port_Type; MCR_Record: in MCR_Record_Type ) is --------------------------------------------------------------------------- use BitsAKD; MCReg: Byte_Type := 16#00#; begin MCReg := Set_Bits ( MCReg, boolean'pos ( MCR_Record.DTR_Active ) * Bit0_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( MCR_Record.RTS_Active ) * Bit1_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( MCR_Record.Hayes_Reset ) * Bit2_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( MCR_Record.Enable_Ints ) * Bit3_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( MCR_Record.UART_Loopback ) * Bit4_Byte ); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( MCR ), MCReg ); end Set_MCR; procedure Set_MCR ( Port: in Port_Type; DTR_Active: in boolean; RTS_Active: in boolean; Hayes_Reset: in boolean; Enable_Ints: in boolean; UART_Loopback: in boolean ) is --------------------------------------------------------------------------- use BitsAKD; MCReg: Byte_Type := 16#00#; begin MCReg := Set_Bits ( MCReg, boolean'pos ( DTR_Active ) * Bit0_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( RTS_Active ) * Bit1_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( Hayes_Reset ) * Bit2_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( Enable_Ints ) * Bit3_Byte ); MCReg := Set_Bits ( MCReg, boolean'pos ( UART_Loopback ) * Bit4_Byte ); PortAKD.Out_Byte ( Port_Base_Address ( Port ) + Offset ( MCR ), MCReg ); end Set_MCR; procedure Setup ( Port: in Port_Type := Com1; BPS: in BPS_Type := 1200; Char_Length: in Char_Length_Type := C8; Stop_Bits: in Stop_Bits_Type := S1; Parity: in Parity_Type_2 := Ignore; Break_Enabled: in boolean := false; Port_Alternate: in boolean := false; DTR_Active: in boolean := true; RTS_Active: in boolean := true; Hayes_Reset: in boolean := false; Enable_Ints: in boolean := true; UART_Loopback: in boolean := false; IE_Data_Received: in boolean := false; IE_THR_Empty: in boolean := false; IE_Data_Error_Break: in boolean := false; IE_MSR_Change: in boolean := false ) is --------------------------------------------------------------------------- -- This version of Setup does not use DOS interrupts. Use this one. -- It might be best to disable interrupts before calling this. --------------------------------------------------------------------------- Dummy_Reg: Byte_Type; begin -- Set the registers Set_BPS ( Port, BPS ); Set_IER ( Port, IE_Data_Received, IE_THR_Empty, IE_Data_Error_Break, IE_MSR_Change ); Set_LCR ( Port, Char_Length, Stop_Bits, Parity, Break_Enabled, Port_Alternate ); Set_MCR ( Port, DTR_Active, RTS_Active, Hayes_Reset, Enable_Ints, UART_Loopback ); -- Clear 8250 status and data registers by reading them -- IIR should be 16#01# otherwise interrupt is pending Dummy_Reg := Get_RDR ( Port ); Dummy_Reg := Get_LSR ( Port ); Dummy_Reg := Get_MSR ( Port ); if Get_IIR ( Port ) /= 16#01# then ScrnAKD.Put_Line ( "Interrupt Identification Register is not 16#01#." ); declare Dum_Str : string ( 1..10 ); Dum_Last : natural; begin TextAKD.Put ( "Please press ENTER to continue..." ); TextAKD.Get_Line ( Dum_Str, Dum_Last ); end; end if; -- Registers_Display ( Registers_Fetch ( Port ) ); exception when others => ErroAKD.Notify ( "CommAKD.Setup (non-DOS)" ); raise; end Setup; procedure Setup ( Port: in Port_Type; Baud_Rate: in Baud_Rate_Type; Char_Length: in Char_Length_Type; Parity: in Parity_Type; Stop_Bits: in Stop_Bits_Type; Status: out integer ) is --------------------------------------------------------------------------- -- This version of Setup uses DOS interrupts. Use the other one. --------------------------------------------------------------------------- R: Interrupt.Registers; use BitsAKD; begin R.AX := ( Char_Length_Type 'pos ( Char_Length ) * 2#000001# ); R.AX := R.AX or ( Stop_Bits_Type 'pos ( Stop_Bits ) * 2#000100# ); R.AX := R.AX or ( Parity_Type 'pos ( Parity ) * 2#001000# ); R.AX := R.AX or ( Baud_Rate_Type 'pos ( Baud_Rate ) * 2#100000# ); R.DX := Port_Type'pos ( Port ); Interrupt.Vector ( 16#14#, R ); Status := R.AX; TextAKD.Put_Line ( Byte_Type'image ( PortAKD.In_Byte ( Port_Base_Address ( Port ) + Offset ( LCR ) ) ) ); end Setup; procedure Status_Display ( Status: in Status_Type ) is --------------------------------------------------------------------------- use BitsAKD; use ScrnAKD; begin ClrScr; Put_Line("Line Status Register (LSR)"); Put_Line; Put(" Data ready.............................."); Put_Line ( "and" ( Bit8_Word, Status ) = Bit8_Word ); Put(" Overrun error..........................."); Put_Line ( "and" ( Bit9_Word, Status ) = Bit9_Word ); Put(" Parity error............................"); Put_Line ( "and" ( Bit10_Word, Status ) = Bit10_Word ); Put(" Framing error..........................."); Put_Line ( "and" ( Bit11_Word, Status ) = Bit11_Word ); Put(" Break detected.........................."); Put_Line ( "and" ( Bit12_Word, Status ) = Bit12_Word ); Put(" Transmit holding register (THR) empty..."); Put_Line ( "and" ( Bit13_Word, Status ) = Bit13_Word ); Put(" Transmit shift register (TSR) empty....."); Put_Line ( "and" ( Bit14_Word, Status ) = Bit14_Word ); Put(" Timeout................................."); Put_Line ( "and" ( Bit15_Word, Status ) = Bit15_Word ); Put_Line; Put_Line("Modem Status Register (MSR)"); Put_Line; Put(" Change in Clear to Send (CTS) status...."); Put_Line ( "and" ( Bit0_Word, Status ) = Bit0_Word ); Put(" Change in Data Set Ready (DSR) status..."); Put_Line ( "and" ( Bit1_Word, Status ) = Bit1_Word ); Put(" Trailing edge ring indicator............"); Put_Line ( "and" ( Bit2_Word, Status ) = Bit2_Word ); Put(" Change in receive line signal..........."); Put_Line ( "and" ( Bit3_Word, Status ) = Bit3_Word ); Put(" Clear to Send (CTS)....................."); Put_Line ( "and" ( Bit4_Word, Status ) = Bit4_Word ); Put(" Data Set Ready (DSR)...................."); Put_Line ( "and" ( Bit5_Word, Status ) = Bit5_Word ); Put(" Ring Indicator (RI)....................."); Put_Line ( "and" ( Bit6_Word, Status ) = Bit6_Word ); Put(" Receive line signal detected............"); Put_Line ( "and" ( Bit7_Word, Status ) = Bit7_Word ); end Status_Display; function Status_Fetch ( Port: in Port_Type ) return Status_Type is --------------------------------------------------------------------------- -- This uses a DOS interrupt. Don't use it. --------------------------------------------------------------------------- R: Interrupt.Registers; begin R.AX := Set_Byte ( R.AX, 16#03#, Low_Byte => false ); R.DX := Port_Type'pos ( Port ); Interrupt.Vector ( 16#14#, R ); return R.AX; end Status_Fetch; function Status_Set ( LSR, MSR: in Byte_Type ) return Status_Type is --------------------------------------------------------------------------- Temp : Word_Type; begin Temp := Set_Byte ( Temp, LSR, Low_Byte => false ); Temp := Set_Byte ( Temp, MSR, Low_Byte => true ); return Temp; end Status_Set; --------------------------------------------------------------------------- --------------------------------------------------------------------------- end CommAKD;