Título: Comunicação Serial
Linguagem: C/C++
S.O.: DOS
Autor(es): Wenderson Teixeira


Comunicação Serial


Serial.h

/*------------------------------------------------------------------*
                          SERIAL.H

              Some definitions used by SERIAL.CPP
*------------------------------------------------------------------*/

#define COM1            1
#define COM2            2
#define COM1BASE        0x3F8   /* Base port address for COM1 */
#define COM2BASE        0x2F8   /* Base port address for COM2 */

/*
  The 8250 UART has 10 registers accessible through 7 port
  addresses. Here are their addresses relative to COM1BASE and
  COM2BASE. Note that the baud rate registers, (DLL) and (DLH)
  are active only when the Divisor-Latch Access-Bit (DLAB) is
  on. The (DLAB) is bit 7 of the (LCR).

      o TXR Output data to the serial port.
      o RXR Input data from the serial port.
      o LCR Initialize the serial port.
      o IER Controls interrupt generation.
      o IIR Identifies interrupts.
      o MCR Send control signals to the modem.
      o LSR Monitor the status of the serial port.
      o MSR Receive status of the modem.
      o DLL Low byte of baud rate divisor.
      o DHH High byte of baud rate divisor.
*/
#define TXR             0       /* Transmit Register (WRITE) */
#define RXR             0       /* Receive Register  (READ)  */
#define IER             1       /* Interrupt Enable          */
#define IIR             2       /* Interrupt ID              */
#define LCR             3       /* Line Control              */
#define MCR             4       /* Modem Control             */
#define LSR             5       /* Line Status               */
#define MSR             6       /* Modem Status              */
#define DLL             0       /* Divisor Latch Low         */
#define DLH             1       /* Divisor Latch High        */

/*------------------------------------------------------------------*
Bit values held in the Line Control Register (LCR).
      bit             meaning
      ---             -------
      0-1             00=5 bits, 01=6 bits, 10=7 bits, 11=8 bits.
      2               Stop bits.
      3               0=parity off, 1=parity on.
      4               0=parity odd, 1=parity even.
      5               Sticky parity.
      6               Set break.
      7               Toggle port addresses.
*------------------------------------------------------------------*/
#define NO_PARITY       0x00
#define EVEN_PARITY     0x18
#define ODD_PARITY      0x08


/*------------------------------------------------------------------*
Bit values held in the Line Status Register (LSR).
      bit             meaning
      ---             -------
      0               Data ready.
      1               Overrun error - Data register overwritten.
      2               Parity error  - bad transmission.
      3               Framing error - No stop bit was found.
      4               Break detect  - End to transmission requested.
      5               Transmitter holding register is empty.
      6               Transmitter shift register is empty.
      7               Time out - off line.
*------------------------------------------------------------------*/
#define RCVRDY          0x01
#define OVRERR          0x02
#define PRTYERR         0x04
#define FRMERR          0x08
#define BRKERR          0x10
#define XMTRDY          0x20
#define XMTRSR          0x40
#define TIMEOUT         0x80

/*------------------------------------------------------------------*
Bit values held in the Modem Output Control Register (MCR).
      bit             meaning
      ---             -------
      0               Data Terminal Ready. Computer ready to go.
      1               Request To Send. Computer wants to send data.
      2               Auxillary output #1.
      3               Auxillary output #2. (Note: This bit must be
                      set to allow the communications card to send
                      interrupts to the system.)
      4               UART ouput looped back as input.
      5-7             Not used.
*------------------------------------------------------------------*/
#define DTR             0x01
#define RTS             0x02
#define MC_INT          0x08


/*------------------------------------------------------------------*
Bit values held in the Modem Input Status Register (MSR).
      bit             meaning
      ---             -------
      0               Delta Clear To Send.
      1               Delta Data Set Ready.
      2               Delta Ring Indicator.
      3               Delta Data Carrier Detect.
      4               Clear To Send.
      5               Data Set Ready.
      6               Ring Indicator.
      7               Data Carrier Detect.
*------------------------------------------------------------------*/
#define CTS             0x10
#define DSR             0x20

/*------------------------------------------------------------------*
Bit values held in the Interrupt Enable Register (IER).
      bit             meaning
      ---             -------
      0               Interrupt when data received.
      1               Interrupt when transmitter holding reg. empty.
      2               Interrupt when data reception error.
      3               Interrupt when change in modem status register.
      4-7             Not used.
*------------------------------------------------------------------*/
#define RX_INT          0x01

/*------------------------------------------------------------------*
Bit values held in the Interrupt Identification Register (IIR).
      bit             meaning
      ---             -------
      0               Interrupt pending.
      1-2             Interrupt ID code.
                      00=Change in modem status register,
                      01=Transmitter holding register empty,
                      10=Data received,
                      11=reception error, or break encountered.
      3-7             Not used.
*------------------------------------------------------------------*/
#define RX_ID           0x04
#define RX_MASK         0x07


/* These are the port addresses of the 8259 Programmable
 Interrupt Controller (PIC). */
#define IMR             0x21   /* Interrupt Mask Register port */
#define ICR             0x20   /* Interrupt Control Port       */


/* An end of interrupt needs to be sent to the Control Port of
 the 8259 when a hardware interrupt ends. */
#define EOI             0x20   /* End Of Interrupt */


/* The (IMR) tells the (PIC) to service an interrupt only if it
 is not masked (FALSE). */
#define IRQ3            0xF7  /* COM2 */
#define IRQ4            0xEF  /* COM1 */

/*-----------------------------------------------------------------*/
#define VERSION 0x0101

#ifndef __cplusplus
  #define   INTERRUPTPARAM
#else
  #define   INTERRUPTPARAM  ...
#endif

#define NOERROR         0       /* No error               */
#define BUFOVFL         1       /* Buffer overflowed      */

#define ASCII           0x007F  /* Mask ASCII characters  */
#define SBUFSIZ         0x4000  /* Serial buffer size     */

#define ESC             0x1B
#define BACKSPACE       0x08
#define CR              0x0D
#define LF              0x0A
#define DEL             0x07
/*-----------------------------------------------------------------*/

#if (__BORLANDC__ <= 0x460) || !defined(__cplusplus)
  typedef enum { false, true } bool;
#endif

typedef struct {
  int port;
  long speed;
  int parity;
  int bits;
  int stopbits;
} TSerialSettings;

void interrupt com_int(INTERRUPTPARAM);

void SerialInit(void);
void SerialClose(void);
bool SerialSetPort(int Port);
bool SerialSetSpeed(long Speed);
bool SerialSetOthers(int Parity, int Bits, int StopBit);
bool SerialSetup(const TSerialSettings *Settings);

bool SerialOut(char x);
bool SerialString(char *string);
int SerialGetChar(void);

void setvects(void);
void resvects(void);
void i_enable(int pnum);
void i_disable(void);
void comm_on(void);
void comm_off(void);

int c_break(void);

extern int SError;
/*-----------------------------------------------------------------*/


Serial.cpp
/*-------------------------------------------------------------*
                          SERIAL.CPP

 * Compile this program with Test Stack Overflow OFF.
*-------------------------------------------------------------*/
#include <dos.h>
#include <stdio.h>

#include "serial.h"

int SError = NOERROR;
int portbase = 0;
void interrupt(*oldvects[2])(INTERRUPTPARAM);

static char ccbuf[SBUFSIZ];
unsigned int startbuf = 0;
unsigned int endbuf = 0;

/* Handle communications interrupts and put them in ccbuf */
void interrupt com_int(INTERRUPTPARAM)
{
  disable();
  if((inportb(portbase + IIR) & RX_MASK) == RX_ID)
  {
    if(((endbuf + 1) & SBUFSIZ - 1) == startbuf)
      SError = BUFOVFL;

    ccbuf[endbuf++] = inportb(portbase + RXR);
    endbuf &= SBUFSIZ - 1;
  }

  /* Signal end of hardware interrupt */
  outportb(ICR, EOI);
  enable();
}

/* Start communication */
void SerialInit(void)
{
  endbuf = startbuf = 0;
  setvects();
  comm_on();
}

/* End communication */
void SerialClose(void)
{
  comm_off();
  resvects();
}

/* Set the port number to use */
bool SerialSetPort(int Port)
{
  int Offset, far *RS232_Addr;

  switch (Port)
  { /* Sort out the base address */
    case COM1:
      Offset = 0x0000;
    break;

    case COM2:
      Offset = 0x0002;
    break;

    default:
    return false;
  }

  RS232_Addr = (int *)MK_FP(0x0040, Offset);  /* Find out where the port is.  */
  if(*RS232_Addr == NULL)
    return false;/* If NULL, then port not used. */
  portbase = *RS232_Addr;              /* Otherwise, set portbase. */

  return true;
}

/* This routine sets the speed; will accept funny baud rates. */
/* Setting the speed requires that the DLAB be set on.        */
bool SerialSetSpeed(long Speed)
{
  char c;
  int divisor;

  if(portbase == 0 || Speed == 0)            /* Avoid divide by zero */
    return false;
  else
    divisor = (int)(115200L / Speed);

  disable();
  c = inportb(portbase + LCR);
  outportb(portbase + LCR, (c | 0x80)); /* Set DLAB   */
  outportb(portbase + DLL, (divisor & 0x00FF));
  outportb(portbase + DLH, ((divisor >> 8) & 0x00FF));
  outportb(portbase + LCR, c);          /* Reset DLAB */
  enable();

  return true;
}

/* Set other communications parameters */
bool SerialSetOthers(int Parity, int Bits, int StopBit)
{
  int setting;

  if(portbase == 0)
    return false;

  if(Bits < 5 || Bits > 8)
    return false;

  if(StopBit != 1 && StopBit != 2)
    return false;

  if(Parity != NO_PARITY && Parity != ODD_PARITY && Parity != EVEN_PARITY)
    return false;

  setting = Bits - 5;
  setting |= ((StopBit == 1) ? 0x00 : 0x04);
  setting |= Parity;

  disable();
  outportb(portbase + LCR, setting);
  enable();

  return true;
}

/* Set up the port */
bool SerialSetup(const TSerialSettings *Settings)
{
  if(!SerialSetPort(Settings->port))
    return false;

  if(!SerialSetSpeed(Settings->speed))
    return false;

  if(!SerialSetOthers(Settings->parity, Settings->bits, Settings->stopbits))
    return false;

  return true;
}

/* Output a character to the serial port */
bool SerialOut(char x)
{
  long int timeout = 0x0000FFFFL;

  outportb(portbase + MCR,  MC_INT | DTR | RTS);

  /* Este trecho e utilizado somente com modem's */
  /* Wait for Clear To Send from modem */
  /*
  while((inportb(portbase + MSR) & CTS) == 0)
    if(!(--timeout))
      return false;
  */

  timeout = 0x0000FFFFL;

  /* Wait for transmitter to clear */
  while((inportb(portbase + LSR) & XMTRDY) == 0)
    if(!(--timeout))
      return false;

  disable();
  outportb(portbase + TXR, x);
  enable();

  return true;
}

/* Output a string to the serial port */
bool SerialString(char *string)
{
  while(*string)
    if(!SerialOut(*string++))
      return false;
  return true;
}

/* This routine returns the current value in the buffer */
int SerialGetChar(void)
{
  int res;

  if(endbuf == startbuf)
    return (-1);

  res = (int)ccbuf[startbuf++];
  startbuf %= SBUFSIZ;
  return res;
}

/* Install our functions to handle communications */
void setvects(void)
{
  oldvects[0] = getvect(0x0B);
  oldvects[1] = getvect(0x0C);
  setvect(0x0B, com_int);
  setvect(0x0C, com_int);
}

/* Uninstall our vectors before exiting the program */
void resvects(void)
{
  setvect(0x0B, oldvects[0]);
  setvect(0x0C, oldvects[1]);
}

/* Turn on communications interrupts */
void i_enable(int pnum)
{
  int c;

  disable();
  c = inportb(portbase + MCR) | MC_INT;
  outportb(portbase + MCR, c);
  outportb(portbase + IER, RX_INT);
  c = inportb(IMR) & (pnum == COM1 ? IRQ4 : IRQ3);
  outportb(IMR, c);
  enable();
}

/* Turn off communications interrupts */
void i_disable(void)
{
  int c;

  disable();
  c = inportb(IMR) | ~IRQ3 | ~IRQ4;
  outportb(IMR, c);
  outportb(portbase + IER, 0);
  c = inportb(portbase + MCR) & ~MC_INT;
  outportb(portbase + MCR, c);
  enable();
}

/* Tell modem that we're ready to go */
void comm_on(void)
{
  int c, pnum;

  pnum = (portbase == COM1BASE ? COM1 : COM2);
  i_enable(pnum);
  c = inportb(portbase + MCR) | DTR | RTS;
  outportb(portbase + MCR, c);
}

/* Go off-line */
void comm_off(void)
{
  i_disable();
  outportb(portbase + MCR, 0);
}

/* Control-Break interrupt handler */
int c_break(void)
{
  i_disable();
  fprintf(stderr, "\nStill online.\n");

  return false;
}


Term.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>
#include <graphics.h>

#include "serial.h"

#define IsStringEqual(a,b)  (strcmpi((a), (b)) == 0)

void ProcessExit()
{
  switch (SError)
  {
    case NOERROR:
      printf("\nbye.\n");
    break;

    case BUFOVFL:
      printf("\nBuffer Overflow.\n");
    break;

    default:
      printf("\nUnknown Error, SError = %d\n", SError);
  }

  SerialClose();
}

bool Save(char *buffer, int count)
{
  FILE *fp = fopen("log.txt", "at");
  if(!fp)
    return false;

  fwrite(buffer, sizeof(char), count, fp);
  return true;
}

TSerialSettings ReadParams(int ArgC, char *ArgV[])
{
  TSerialSettings settings = { COM2, 115200L, NO_PARITY, 8, 1 };
  char *strSettings, *pTok;

  if(ArgC < 2)
    return settings;

  if(IsStringEqual(ArgV[1], "/h"))
  {
    printf("Uso:\n  serial Port:Speed,Bits,Parity,Stopbits\n"
           "    Port     - COM1, COM2*\n"
           "    Speed    - 1200, 2400, 9600, 19200, 38400, 57600, 115200*\n"
           "    Bits     - 5,6,7,8*\n"
           "    Parity   - n*, e, o\n"
           "    Stopbits - 1*, 2\n\n"
           "Ex.: serial COM2:19200,8,n,1\n");
    exit(0);
  }

  strSettings = strdup(ArgV[1]);
  if(!strSettings)
    return settings;

  pTok = strtok(strSettings, ":");
  settings.port = pTok ? (IsStringEqual(pTok, "com1") ? COM1 : COM2 ) : COM2;

  pTok = strtok(0, ",");
  settings.speed = pTok ? atol(pTok) : 115200L;

  pTok = strtok(0, ",");
  settings.bits = pTok ? atoi(pTok) : 8;

  pTok = strtok(0, ",");
  settings.parity = pTok ?
                      (IsStringEqual(pTok, "n") ? NO_PARITY :
                       IsStringEqual(pTok, "e") ? EVEN_PARITY :
                       IsStringEqual(pTok, "o") ? ODD_PARITY : NO_PARITY)
                       : NO_PARITY;

  pTok = strtok(0, ",");
  settings.stopbits = pTok ? atoi(pTok) : 1;
  free(strSettings);

  return settings;
}

int main(int ArgC, char *ArgV[])
{
  TSerialSettings settings = ReadParams(ArgC, ArgV);
  char *buffer = 0;
  int byteCounter = 0;
  unsigned long totalCounter = 0;

  int c, done  = false;

  buffer = (char *)malloc(sizeof(char) * 1024);
  if(!buffer)
  {
    printf("Erro de alocação de memória.\n\r");
    return (99);
  }

  if(!SerialSetup(&settings))
  {
    printf("Erro de inicialização da serial.\n\r");
    return (99);
  }

  atexit(ProcessExit);

  SerialInit();

  printf("//////////// Termial Simples \\\\\\\\\\\\\\\\\\\\\\\\\n");
  printf("\nMODO - COM%d:%ld,%d,%s,%d\n", settings.port, settings.speed, settings.bits,
         (settings.parity == NO_PARITY ? "None" : (settings.parity == EVEN_PARITY ? "Even" : "Odd")), 
         settings.stopbits);

  printf("\n ...Pressione [ESC] para sair... \n");

  ctrlbrk(c_break);

  do
  {
    if(kbhit())
    {
      c = getch();
      switch(c ? c : getch())
      {
        default:
          if(!SerialOut(c))
            printf("\nFalha na transmissão.\n");
        break;

        case ESC:
          done = true;
          if(byteCounter)
            Save(buffer, byteCounter);
        break;
      }
    }

    c = SerialGetChar();
    if (c != -1)
    {
      int y;

      buffer[byteCounter++] = c == CR ? LF : c;

      switch(c)
      {
        //case LF:
        //case CR:
        //break;

        case DEL:
          clrscr();
        break;

        default:
          printf("%c", c /*& ASCII*/);
      }

      if(byteCounter == 1024 || c == LF || c == CR)
      {
        Save(buffer, byteCounter);
        byteCounter = 0;
      }

      totalCounter++;
    }

  } while(!done && !SError);

  printf("\n\nBytes Recebidos: %lu", totalCounter);
  
  if(SError == NOERROR)
    return 0;
  else
    return 99;
}






1