I know the rules state that I'm not allowed to let you answer this question for me, since it's for school. But directing me in the right way would be more than helpful.
Basically I have a lab from last semester that is basic communication over serial using a defeated Null Modem Cable, but now we are given a full handshake cable (with CTS and RTS lines, etc) and must implement hardware flow control (and modify the old lab to allow this). What I know is that we must use CTS (Clear to Send), RTS (Request to Send), MCR (Modem Control Register), and MSR (Modem Status Register) to accomplish this.
It is surprisingly difficult to find examples in C (especially for DOS) of how exactly to do this. We were never actually taught this and it was one of those "research this on your own time" type of things.
If it helps, here is the code from last semester, just to give you an idea of what functions and includes we are using (conio.h, outportb(), inportb(), etc). WARNING: LONG CODE UP AHEAD!
==========================
==========
==========
======
/* Included Libraries */
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Key Defines (ESC, F1, F2, F3, F4, F5) */
#define KEY_ESC 27
#define KEY_F1 59
#define KEY_F2 60
#define KEY_F3 61
#define KEY_F4 62
#define KEY_F5 63
#define KEY_F6 64
#define KEY_F7 65
/* Defines */
// COM1 0x3F8
// COM2 0x2F8
// COM3 0x3E8
// COM4 0x2E8
#define WALK_SIZE 80 /* Length of walking string */
#define MAX_STRING 32 /* Max lengt of input strings */
#define BUFFER_SIZE 1024 /* Max buffer size for rx in */
#define S_PORT 0x3f8 /* Serial port */
#define INTMASK 0x21 /* Interrupt Mask */
#define INTVECT 0x0C /* Interrupt Vector */
#define IER ( S_PORT + 1 ) /* Interrupt Enable Register */
#define IIR ( S_PORT + 2 ) /* Interrupt ID Register */
#define LCR ( S_PORT + 3 ) /* Line Control Register */
#define MCR ( S_PORT + 4 ) /* Modem Control Register */
#define LSR ( S_PORT + 5 ) /* Line Status Register */
#define MSR ( S_PORT + 6 ) /* Modem Status Register */
#define DLAB_LOW ( S_PORT + 0 ) /* DLAB Low Bit */
#define DLAB_HIGH ( S_PORT + 1 ) /* DLAB High Bit */
#define DLAB 0x80 /* Divisor Latch Access Bit */
#define SBITS1 0x00 /* Stop Bits (1) */
#define SBITS2 0x04 /* Stop Bits (2) */
#define NBITS7 0x02 /* Data Bits (7) */
#define NBITS8 0x03 /* Data Bits (8) */
#define EVENPARITY 0x18 /* Parity Bits (EVEN) */
#define NOPARITY 0x00 /* Parity Bits (NONE) */
#define ODDPARITY 0x08 /* Parity Bits (ODD) */
#define SPACEPARITY 0x38 /* Parity Bits (SPACE) */
#define MARKPARITY 0x28 /* Parity Bits (MARK) */
#define BR37 0xC00 /* Baud Rate (37) */
#define BR75 0x600 /* Baud Rate (75) */
#define BR150 0x300 /* Baud Rate (150) */
#define BR300 0x180 /* Baud Rate (300) */
#define BR600 0xC0 /* Baud Rate (600) */
#define BR1200 0x60 /* Baud Rate (1200) */
#define BR2400 0x30 /* Baud Rate (2400) */
#define BR4800 0x18 /* Baud Rate (4800) */
#define BR9600 0x0C /* Baud Rate (9600) */
#define BR19200 0x06 /* Baud Rate (19200) */
#define BR38400 0x03 /* Baud Rate (38400) */
#define BR57600 0x02 /* Baud Rate (57600) */
#define BR115200 0x01 /* Baud Rate (115200) */
/* Start of Global Variables */
int bufferpos, /* Keep track of current buffer position. */
currentbuf;
char receivebuffer [ BUFFER_SIZE ], /* Receive Buffer. */
argument [ MAX_STRING ], /* Command line arguments */
setting [ MAX_STRING ], /* Left side of a=b arg. */
value [ MAX_STRING ]; /* Right side of a=b arg. */
unsigned long int baudrate = BR2400, /* Default Baud value */
numbits = NBITS8, /* Default Data bit value */
numstopbits = SBITS1, /* Default Stop bit value */
parity = ODDPARITY; /* Default Parity value */
/* Function Prototypes */
void interrupt rxchar ( void );
void interrupt ( * old_int ) ( );
void parse_string ( void );
void parse_params ( void );
void walk_pattern ( void );
/* Our Main */
int main ( int argc, char *argv[] )
{
int i;
char chartoprint, txchar;
printf ( "\n" );
/* If there is at least one arguments from the command line, *
* and no more than 4, then let's parse them. */
if ( argc >= 2 && argc <= 5 )
{
for ( i=1; i < argc; i ++ )
{
/* Copy each arg to "argument", and then first *
* parse the string to get the setting and value. *
* Then pass both to parse_params which takes care *
* of all the input parameters. */
strcpy ( argument, argv[i] );
parse_string ( );
parse_params ( );
}
}
/* Otherwise, there are no parameters, or too many. So just use *
* default values. */
else
{
printf ( "\n" );
printf ( "No parameters were entered.\n" );
printf ( "Using default.\n\n" );
}
/* Print of the Hex values of all the Serial Port values */
printf ( "Baud Rate: 0x%x\n", baudrate );
printf ( "Parity: 0x%x\n", parity );
printf ( "Stop Bits: 0x%x\n", numstopbits );
printf ( "Number of Bits: 0x%x\n\n", numbits );
disable ( ); /* Disable interrupts while we prepare the serial port. */
/* Preparing the serial ports */
outportb ( IER, 0x00 );
old_int = getvect ( INTVECT );
setvect ( INTVECT, rxchar );
outportb ( LCR, DLAB );
outportb ( DLAB_LOW, baudrate );
outportb ( DLAB_HIGH, 0x00 );
outportb ( LCR, numbits | parity | numstopbits );
outportb ( IIR, 0xC7 );
outportb ( MCR, 0x0B );
outportb ( INTMASK, ( inportb ( INTMASK ) ) &0xEF );
outportb ( IER, 0x01 );
enable ( ); /* Renabling interrupts since we're done preparing */
do
{
//rxchar (); /* Polling the serial ports for new characters */
delay ( 10 );
/* If the buffer position that has been read, does not *
* equal the current buffer position (of the available *
* read in buffer), then we have to read it in. */
if ( bufferpos != currentbuf )
{
/* Get the character to print from the buffer */
chartoprint = receivebuffer [ currentbuf ];
/* Increase the buffer position */
currentbuf++;
/* If the position is over the buffer size, wrap around */
if ( currentbuf >= BUFFER_SIZE ) currentbuf = 0;
/* If the host has sent the F5 key, they are requesting *
* to clear our screen. So let's clear it. */
if ( chartoprint == KEY_F5 ) system ( "cls" );
else printf ( "%c", chartoprint );
}
/* If there is a character being pressed on the keyboard .. */
if ( kbhit ( ) )
{
txchar = getch ( );
switch ( txchar )
{
case KEY_F1: walk_pattern (); break;
case KEY_F2: disable (); break;
case KEY_F3: enable (); break;
case KEY_F4: system ("cls"); break;
case KEY_ESC: break;
default: outportb(S_PORT, txchar);
}
}
} while ( txchar != KEY_ESC );
outportb ( IER, 0 );
outportb ( INTMASK, ( inportb ( INTMASK ) | 0x10 ) );
setvect ( INTVECT, old_int );
return 0;
}
/* Send 80 characters of our walking pattern. */
void walk_pattern ( )
{
int thischar = 'A', i;
for ( i = 0; i < WALK_SIZE; i ++ )
{
outportb ( S_PORT, thischar );
thischar ++;
}
return;
}
/* Parse the args that were passed in from the command line
* that were in the format setting=value. */
void parse_string ( )
{
int counter1 = 0, counter2 = 0;
while ( ( argument[counter1] != '=' ) && ( argument[counter1] != '\0' ) )
{
setting [counter1] = argument [counter1];
counter1++;
}
setting [counter1] = '\0';
counter1 ++;
while ( argument [counter1] != '\0' )
{
value [counter2] = argument [counter1];
counter1 ++;
counter2 ++;
}
value [counter2] = '\0';
}
/* After we have parsed the paramters from the command line, we can
* now get these values and place them in our serial port parameter
* variables */
void parse_params ()
{
long int baud_in,
stop_in,
parity_in,
bytes_in;
if ( !strcmp ( setting, "baud" ) )
{
baud_in = atoi(value);
if ( baud_in == 37 ) baudrate = BR37;
else if ( baud_in == 75 ) baudrate = BR75;
else if ( baud_in == 150 ) baudrate = BR150;
else if ( baud_in == 300 ) baudrate = BR300;
else if ( baud_in == 600 ) baudrate = BR600;
else if ( baud_in == 1200 ) baudrate = BR1200;
else if ( baud_in == 2400 ) baudrate = BR2400;
else if ( baud_in == 4800 ) baudrate = BR4800;
else if ( baud_in == 9600 ) baudrate = BR9600;
else if ( baud_in == 19200 ) baudrate = BR19200;
else if ( baud_in == 38400 ) baudrate = BR38400;
else baudrate = BR2400;
}
if ( !strcmp ( setting, "stop") )
{
stop_in = atoi ( value );
if ( stop_in == 2 ) numstopbits = SBITS2;
else numstopbits = SBITS1;
}
if ( !strcmp (setting, "bits") )
{
bytes_in = atoi ( value );
if ( bytes_in == 7 ) numbits = NBITS7;
else numbits = NBITS8;
}
if ( !strcmp(setting, "parity" ) )
{
if ( !strcmp ( value, "even" ) ) parity = EVENPARITY;
else if ( !strcmp ( value, "none" ) ) parity = NOPARITY;
else if ( !strcmp ( value, "space" ) ) parity = SPACEPARITY;
else if ( !strcmp ( value, "mark" ) ) parity = MARKPARITY;
else parity = ODDPARITY;
}
}
/* Polling the serial port for new available data */
void interrupt rxchar()
{
int checkport = inportb ( LSR );
while ( checkport & 1 )
{
if ( bufferpos >= BUFFER_SIZE ) bufferpos = 0;
receivebuffer [bufferpos] = inportb ( S_PORT );
bufferpos ++;
outportb ( 0x20 , 0x20 );
checkport = inportb ( LSR );
}
}
==========================
==========
==========
======
I know the parsing and stuff is pretty ugly (using global variables and all). This was actually modified from basic template we were given, so don't blame that on me :P
Basically all this does is allows you to enter certain baudrates and parity bits etc, if you want to. If you don't, it will use a default value. Then it will communicate with the other machine over COM1 using the Null Modem cable.
What I'm asking is what type of code would I have to add to implement hardware flow control? I am terrible with this communication stuff, so any examples or guides you can direct me to would be great.
Thank you.
Start Free Trial