home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
10
/
embedcp
/
code
/
comm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-27
|
6KB
|
218 lines
// MIOTDREM - Async link routines
// ------------------------------
//
// Copyright (c) 1991, Stuart G. Phillips. All rights reserved.
//
// Permission is granted for non-commercial use of this software.
// You are expressly prohibited from selling this software in any form,
// distributing it with another product, or removing this notice.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// This module contains the routines that handle the async link between
// MIO and TD.
//
//
#include "miotdr.h"
#include "mio.h"
#include "8530.h"
// #define SERIAL_DEBUG to include status of the communications
// activity. Useful when porting to a new platform in order to
// see what's going on !
#ifdef SERIAL_DEBUG
struct comm_region { unsigned short status;
unsigned short scc_status;
unsigned short scc_special;
unsigned short int_cnt;
unsigned short rx_cnt;
unsigned short tx_cnt;
unsigned char command;
};
static struct comm_region *creg = (struct comm_region *)0x80;
#endif
// Static declarations
static void interrupt scc_int();
void send(unsigned char *buffer,
unsigned short length)
{
// Send a packet of [length] bytes to the other end
// Send the length and look for a NULL byte ack
disable();
scc_write(TDSCC|CMD,R1,0); // Disable receive interrupts
// Wait for TX Buffer emp
while (scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP != Tx_BUF_EMP) ;
scc_wdata(TDSCC|DATA,(unsigned char) length);
#ifdef SERIAL_DEBUG
creg->tx_cnt++;
#endif
while ((scc_read(TDSCC|CMD,R0) & Rx_CH_AV) != Rx_CH_AV) ;
(void) scc_rdata(TDSCC|DATA); // Discard the NULL
// Now send the data
while (length--){
while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
scc_wdata(TDSCC|DATA,*buffer++);
#ifdef SERIAL_DEBUG
creg->tx_cnt++;
#endif
}
scc_write(TDSCC|CMD,R1,INT_ALL_Rx); // Re-enable receive interrupts
enable();
}
void send_ack()
{
// Send a NULL packet as an acknowledgment
disable();
while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
scc_wdata(TDSCC|DATA,0);
#ifdef SERIAL_DEBUG
creg->tx_cnt++;
#endif
enable();
}
void comm_init()
{
unsigned char data;
// Set up SCC - this takes a while !
scc_write(TDSCC|CMD,R9,FHWRES); // Reset the SCC
// Loop a while to let reset complete
for (int i=0; i<256; i++) ;
// Set SCC interrupt handler
setvect(0x06,scc_int);
// Set SCC interupt vector and enables
scc_write(TDSCC|CMD,R2,0x06);
scc_write(TDSCC|CMD,R9,MIE);
scc_write(TDSCC|CMD,R1,INT_ALL_Rx);
// Set Async mode, 8 bits Tx/Rx, 1 stop bit, No parity
scc_write(TDSCC|CMD,R5,DTR|Tx8|TxENAB|RTS);
scc_write(TDSCC|CMD,R3,Rx8|RxENABLE);
// Set Baud rate generator constant
// Using 16x clock
// 9.6 Kbps - 24 (0.16% error - 9615 bps)
// 19.2 Kbps - 11 (0.16% error - 19230 bps)
//
// Using 1x clock
// 38.4 Kbps - 102 (0.16% error - 38461 bps)
// 115.0 Kbps - 32 (2.30% error - 117647 bps)
scc_write(TDSCC|CMD,R4,X16CLK|SB1);
scc_write(TDSCC|CMD,R12,11);
scc_write(TDSCC|CMD,R13,0);
// Set Baud rate generator source and enable
scc_write(TDSCC|CMD,R11,RCBR|TCBR);
scc_write(TDSCC|CMD,R14,SSBR|BRSRC|BRENABL);
// Enable 'slave' interupts
data = inportb(IMKW);
outportb(IMKW,data&~(1 << IRQ7));
enable();
}
static void interrupt scc_int()
{
// Interrupts only on receive character or special status change
unsigned char status;
register unsigned char length;
register unsigned char *rxb = (unsigned char *)rx_buffer;
status = scc_read(TDSCC|CMD,R0);
(void) scc_read(TDSCC|CMD,R1);
#ifdef SERIAL_DEBUG
creg->int_cnt++;
#endif
if (status & Rx_CH_AV){
length = scc_rdata(TDSCC|DATA);
#ifdef SERIAL_DEBUG
creg->status = length;
creg->rx_cnt++;
#endif
// A block of [length] bytes follows
// A zero count is treated specially - used in the initial handshake
if (length == 0)
*rxb = TD_SYNC;
else {
// Send a NULL acknowledgement
while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
scc_wdata(TDSCC|DATA,0);
#ifdef SERIAL_DEBUG
creg->tx_cnt++;
#endif
while (length--){
while ((scc_read(TDSCC|CMD,R0) & Rx_CH_AV) != Rx_CH_AV) ;
*rxb++ = scc_rdata(TDSCC|DATA);
#ifdef SERIAL_DEBUG
creg->rx_cnt++;
#endif
}
}
msgq = (struct td_imsg *)rx_buffer;
}
scc_write(TDSCC|CMD,R0,ERR_RES); // Clear special status
scc_write(TDSCC|CMD,R0,RES_H_IUS); // Reset so we can get next intr.
outportb(IMDW,ISEOI|IRQ7); // Specific end of intr. to PIC
// Check queued packet to determine if TD issued a stop command.
// If it did, assume that we're running as an interrupt to program
// under test - call mc_stop() to return control to MIOTDREM
if (msgq->cmd == TD_STOP)
mc_stop();
}