Files
TempleOS-Rijn/LT/Adam/Comm.APZ
T
2018-09-08 21:45:20 +02:00

253 lines
6.3 KiB
Plaintext

#help_index "Comm"
#help_file "::/LT/Doc/Comm.TXZ"
#define EXCP_TIMEOUT 0x100
#define EXCP_RESET 0x101
#define CH_XOFF 0x13
#define CH_XON 0x11
#define UART_THR 0
#define UART_RDR 0
#define UART_BRDL 0
#define UART_IER 1
#define UART_BRDH 1
#define UART_IIR 2
#define UART_LCR 3
#define UART_MCR 4
#define UART_LSR 5
#define UART_MSR 6
#define COMMf_INCOMING_XOFFED 0
#define COMMf_INCOMING_XOFFED2 1
#define COMMf_INCOMING_XOFFED3 2
#define COMMf_OUTGOING_XOFFED 3
#define COMMf_TX_XOFF 4
#define COMMf_TX_XON 5
U8 comm_base[5]={0,0x3F8,0x2F8,0x3E8,0x2E8};
U1Fifo *comm_Rx_fifos[5]={NULL,NULL,NULL,NULL,NULL};
U1Fifo *comm_Tx_fifos[5]={NULL,NULL,NULL,NULL,NULL};
U8 comm_flags[5]={0,0,0,0,0};
LTChnl *comm_chnls[5]={NULL,NULL,NULL,NULL,NULL};
public void RmtClose(LTChnl *chnl)
{
U8 base;
U8 old_flags=GetFlags;
if (!chnl || !chnl->type) return;
if (chnl->type==LCT_COMM) {
base=comm_base[chnl->port];
OutP(base+UART_IER,0);
Cli;
if (comm_Rx_fifos[chnl->port]) {
DelU1Fifo(comm_Rx_fifos[chnl->port]);
comm_Rx_fifos[chnl->port]=NULL;
}
if (comm_Tx_fifos[chnl->port]) {
DelU1Fifo(comm_Tx_fifos[chnl->port]);
comm_Tx_fifos[chnl->port]=NULL;
}
comm_chnls[chnl->port]=NULL;
SetFlags(old_flags);
}
AFree(chnl);
}
public void CommPutChar(U8 port,U1 b)
{
U8 old_flags=GetFlags;
U8 base=comm_base[port];
Cli;
if (b==CH_XOFF)
Bts(&comm_flags[port],COMMf_TX_XOFF);
else if (b==CH_XON)
Bts(&comm_flags[port],COMMf_TX_XON);
else {
if (U1FifoCnt(comm_Tx_fifos[port])>comm_Tx_fifos[port]->mask-4) {
Sti;
while (U1FifoCnt(comm_Tx_fifos[port])>comm_Tx_fifos[port]->mask>>1)
SwapInNext;
Cli;
}
if (Bt(&comm_flags[port],COMMf_OUTGOING_XOFFED)) {
Sti;
while (Bt(&comm_flags[port],COMMf_OUTGOING_XOFFED))
SwapInNext;
Cli;
}
if (comm_Tx_fifos[port])
U1FifoInsert(comm_Tx_fifos[port],b);
}
OutP(base+UART_IER,3); //Enable TX & RX IRQ
SetFlags(old_flags);
}
U8 dc_rx=0,dc_tx=0;
void CommRxTxChar(U8 port)
{
U8 i=0,ch=0,irq,base=comm_base[port];
BoolU4 have_one;
BoolU4 old_raw=Raw(ON);
if (comm_Rx_fifos[port] &&
comm_Tx_fifos[port]) {
while (i++<4) {
irq=InP(base+UART_IIR);
if ((irq & 0x07)==4) { //RX IRQ
ch=InP(base+UART_RDR);
if (ch==CH_XOFF)
Bts(&comm_flags[port],COMMf_OUTGOING_XOFFED);
else if (ch==CH_XON)
Btr(&comm_flags[port],COMMf_OUTGOING_XOFFED);
else {
U1FifoInsert(comm_Rx_fifos[port],ch);
if (U1FifoCnt(comm_Rx_fifos[port])>comm_Rx_fifos[port]->mask>>1) {
CommPutChar(port,CH_XOFF);
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED2);
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED3);
}
}
} else if ((irq & 0x07)==2) { //TX IRQ
have_one=TRUE;
if (Btr(&comm_flags[port],COMMf_TX_XOFF))
ch=CH_XOFF;
else if (Btr(&comm_flags[port],COMMf_TX_XON))
ch=CH_XON;
else if (!U1FifoRemove(comm_Tx_fifos[port],&ch))
have_one=FALSE;
if (have_one) {
if (ch==CH_XOFF)
Bts(&comm_flags[port],COMMf_INCOMING_XOFFED);
else if (ch==CH_XON) {
if (!Btr(&comm_flags[port],COMMf_INCOMING_XOFFED3)) {
if (!Btr(&comm_flags[port],COMMf_INCOMING_XOFFED2))
Btr(&comm_flags[port],COMMf_INCOMING_XOFFED);
else
Bts(&comm_flags[port],COMMf_TX_XON);
} else
Bts(&comm_flags[port],COMMf_TX_XON);
}
OutP(base+UART_THR,ch);
}
if (!U1FifoCnt(comm_Tx_fifos[port]) &&
!Bt(&comm_flags[port],COMMf_INCOMING_XOFFED))
OutP(base+UART_IER,1); //Enable RX IRQ
} else
break;
}
}
Raw(old_raw);
}
void Irq03Handler()
{
CommRxTxChar(2);
CommRxTxChar(4);
}
void Irq04Handler()
{
CommRxTxChar(1);
CommRxTxChar(3);
}
public U1 CommGetChar(U8 port)
{
U8 ch=0;
while (!U1FifoRemove(comm_Rx_fifos[port],&ch))
SwapInNext;
if (Bt(&comm_flags[port],COMMf_INCOMING_XOFFED) &&
U1FifoCnt(comm_Rx_fifos[port])<comm_Rx_fifos[port]->mask>>2)
CommPutChar(port,CH_XON);
return ch;
}
public BoolU4 CommScanChar(U8 port,U1 *ch)
{
U8 ch1=0;
if (U1FifoPeek(comm_Rx_fifos[port],&ch1)) {
U1FifoRemove(comm_Rx_fifos[port],&ch1);
*ch=ch1;
if (Bt(&comm_flags[port],COMMf_INCOMING_XOFFED) &&
U1FifoCnt(comm_Rx_fifos[port])<comm_Rx_fifos[port]->mask>>2)
CommPutChar(port,CH_XON);
return TRUE;
} else
return FALSE;
}
void CommRmtPutChar(LTChnl *chnl,U1 b)
{
CommPutChar(chnl->port,b);
}
U1 CommRmtGetChar(LTChnl *chnl)
{
return CommGetChar(chnl->port);
}
BoolU8 CommRmtScanChar(LTChnl *chnl,U1 *ch)
{
return CommScanChar(chnl->port,ch);
}
public LTChnl *CommOpen8N1(U8 port=1,U8 baud=38400)
{
LTChnl *chnl=NULL;
U8 old_flags=GetFlags,base=comm_base[port];
Cli;
if (!port || port>4 || comm_chnls[port])
goto co_exit;
chnl=AMAllocZ(sizeof(LTChnl));
comm_chnls[port]=chnl;
chnl->type=LCT_COMM;
base=comm_base[port];
chnl->port=port;
chnl->baud=baud;
chnl->PutChar=&CommRmtPutChar;
chnl->GetChar=&CommRmtGetChar;
chnl->ScanChar=&CommRmtScanChar;
if (comm_Rx_fifos[chnl->port])
DelU1Fifo(comm_Rx_fifos[chnl->port]);
if (comm_Tx_fifos[chnl->port])
DelU1Fifo(comm_Tx_fifos[chnl->port]);
comm_flags[chnl->port]=0;
comm_Rx_fifos[chnl->port]=NewU1Fifo(0x1000,adam_tss); //must be power of 2
comm_Tx_fifos[chnl->port]=NewU1Fifo(0x1000,adam_tss); //must be power of 2
OutP(base+UART_LCR,0); //Set for IER
OutP(base+UART_IER,0);
OutP(base+UART_LCR,0x80); //Enable baud rate control
OutP(base+UART_BRDL,(0x180/(baud/300)) & 0xFF); //LSB
OutP(base+UART_BRDH,(0x180/(baud/300)) / 256); //MSB
OutP(base+UART_LCR,3); // 8-none-1
InP(base+UART_RDR); //read garbage
InP(base+UART_LSR);
OutP(base+UART_MCR,4);
OutP(base+UART_IER,0); //DIsable all IRQ
OutP(base+UART_MCR,0xA); //out2 and rts
OutP(base+UART_IER,1); //Enable RX IRQ
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED);
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED2);
Bts(&comm_flags[chnl->port],COMMf_INCOMING_XOFFED3);
CommPutChar(chnl->port,CH_XON);
co_exit:
SetFlags(old_flags);
return chnl;
}
public void CommClose(U8 port)
{
LTChnl *chnl=comm_chnls[port];
RmtClose(chnl);
}
ext[EXT_IRQ03]=&Irq03Handler;
ext[EXT_IRQ04]=&Irq04Handler;
#help_index ""