Category : Files from Magazines
Archive   : CUJ9301.ZIP
Filename : 1101057A

 
Output of file : 1101057A contained in archive : CUJ9301.ZIP
#include
#include "tserial.h"
#include
#include
#include
#include

// interrupt functions.
typedef void interrupt far intFunc(...);

// Programmed Interrupt Controller constants.
const PIC0 = 0x20;
const PIC1 = 0x21;
const EOI = 0x20;

// Offsets from port address.
const InterruptEnable = 1,
InterruptIdent = 2,
ModemControl = 4,
LineStatus = 5,
ModemStatus = 6;

// Value for the modem control register.
const ModemControlValue = 11;

// A serial port circular buffer class. There
// are only two instances of this class, one
// for each port COM1, and COM2. They are
// static globals, and are initailized before
// main(). They contain a circular buffer,
// the port number and port address, and the
// interrupt vector they replace, so that
// they can be restored at destruction. This
// is not a complete or robust class, and is
// private to this module. It is intended
// only for use by SerialStream.
class ComBuffer {
public:
// Size of circular buffer
enum { BufSize = 0x100 };
// Default constructor.
ComBuffer();
~ComBuffer();
// Set up vector, and enables interrupts
void hookInterrupt();
// Get a single character from the buffer
int getc();
// Send a single character to the port
void putc(int c);
// Read the line status register.
int status() const
{
return ::inp(portAddr+LineStatus);
}
// Check if characters are available
int avail() const
{
return in != out;
}
// Receive a character from port. This function
// is called by the interrupt routine.
void receive();
private:
// The mask needed for setting the PIC.
int interruptMask(int port) const
{
return 1 << (4 - port);
}
// The interrupt number for each port.
int interruptVec(int port) const
{
return 12 - port;
}
char *in, *out, *buff; // The circular buffer
int port; // The port number 0-1
int portAddr; // The port address
intFunc *oldVector; // The previos vector
static int initPort;
};

// initPort is used by the constructor to initialize
// the ports in sequence.
int ComBuffer::initPort = 0;
// Only two ports are set up here. If you add more
// you need to identify the port addresses and
// interrupt vectors.
static ComBuffer CommPorts[2];

// Initialize the buffers. Allocate the circular
// buffer, set the in/out pointers, set the port
// and port address values, and clear the old
// vector value.
ComBuffer::ComBuffer()
: buff(new char[BufSize]), port(initPort++),
oldVector(0)
{
// this line is for sceptics to see initializing.
cout << "initializing port #" << port << endl;
portAddr = port ? 0x2f8 : 0x3f8;
in = out = buff;
}

// Delete the circular buffer. If the old vector
// is a valid address, restore it.
ComBuffer::~ComBuffer()
{
// another line for sceptics.
cout << "de-initializing port #" << port << endl;
if(oldVector)
::setvect(interruptVec(port),oldVector);
delete[] buff;
}

// These two routines reset to PIC, and put
// the new character in the buffer
void interrupt far comInterrupt0(...)
{
::outp(PIC0,EOI);
CommPorts[0].receive();
}

void interrupt far comInterrupt1(...)
{
::outp(PIC0,EOI);
CommPorts[1].receive();
}

// This function sets up the interrupts, and
// enables the PIC
void
ComBuffer::hookInterrupt()
{
if(oldVector == 0)
oldVector = ::getvect(interruptVec(port));
switch(port)
{
case 0:
::setvect(interruptVec(port),comInterrupt0);
break;
case 1:
::setvect(interruptVec(port),comInterrupt1);
break;
default:
return;
}
::outp(portAddr+ModemControl,
::inp(portAddr+ModemControl)|ModemControlValue);
::outp(PIC1,::inp(PIC1) & ~interruptMask(port));
::outp(portAddr+InterruptEnable,1);
::outp(PIC0, EOI);
::inp(portAddr);
::inp(portAddr+InterruptIdent);
::inp(portAddr+ModemStatus);
status(); // clear status reg.
}

// Receive a byte from the port and place in the
// circular buffer, called from the interrupt
// handler.
void
ComBuffer::receive()
{
if(in == buff + BufSize)
in = buff; // circular buffer
*in++ = ::inp(portAddr);
}

// Get a character from the circular buffer.
int
ComBuffer::getc()
{
while(!avail())
if(::kbhit())
return -1;
if(out == buff + BufSize)
out = buff; // circular buffer
return *out++;
}

// Send a character directly to the port
void
ComBuffer::putc(int c)
{
while((status() & 0x20) == 0)
if(::kbhit())
return;
::outp(portAddr, c);
}

const default_init = _COM_1200|_COM_CHR8|
_COM_STOP1|_COM_NOPARITY;

// The open function needs to translate the name
// to the port number, initialize the port, and
// enable interrupts.
int SerialStream::open(const char *name, int, int)
{
if(::stricmp(name,"COM1") == 0)
port = 0;
else if(::stricmp(name, "COM2") == 0)
port = 1;
else
return -1;
unsigned int stat = ::_bios_serialcom(
_COM_INIT,port,default_init);
buffPtr = CommPorts+port;
buffPtr->hookInterrupt();
if(stat & 0xFF00)
return -1;
return 0;
}

// The close routine sets the port number to -1
// to indicate it's closed
int
SerialStream::close()
{
port = -1;
return 0;
}

// The read routine repeatedly calls ComBuffer::getc
// to fill it's buffer. len should always be 1.
int SerialStream::read(char *b, size_t len)
{
for(int i = 0; i < len; i++)
b[i] = buffPtr->getc();
return i;
}

// The write routine repeatedly calls ComBuffer::putc
// to empty it's buffer. len should alway be 1.
int SerialStream::write(char *b, size_t len)
{
for(int i = 0; i < len; i++)
buffPtr->putc(b[i]);
return i;
}



  3 Responses to “Category : Files from Magazines
Archive   : CUJ9301.ZIP
Filename : 1101057A

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/