www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2007/07/22/04:32:04

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
NNTP-Posting-Date: Sun, 22 Jul 2007 03:28:16 -0500
From: "Alexei A. Frounze" <alexfru AT chat DOT ru>
Newsgroups: comp.os.msdos.djgpp
References: <f7lfo2$bql$1 AT atlantis DOT news DOT tpi DOT pl> <nIGdnfixh_KlmwLbnZ2dnUVZ_t63nZ2d AT comcast DOT com> <f7nljm$1u8$1 AT atlantis DOT news DOT tpi DOT pl>
Subject: Re: RS232 transmission sometimes fail on AM2
Date: Sun, 22 Jul 2007 01:26:05 -0700
MIME-Version: 1.0
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2900.3138
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3138
Message-ID: <kOqdnWuA_LS9iD7bnZ2dnUVZ_tOtnZ2d@comcast.com>
Lines: 407
X-Usenet-Provider: http://www.giganews.com
NNTP-Posting-Host: 67.170.73.174
X-Trace: sv3-v2N6Hqutra6thsb2BCimvDBR7VbUUwG+Eg86K5ZzblZ8IV3rYEy3tGLElDCRNQ1xxU/wuMFjhGPMS/V!iO4QIVMrNrztzR/KgD3uSe4PzM3rh5SAI2tyAcByLETbpesiEgErlGVpk97IAvXLc+Lg54yQgOJf!+FB374XGvDnQ0rKD9LdvNTwQsvbdhA==
X-Complaints-To: abuse AT comcast DOT net
X-DMCA-Complaints-To: dmca AT comcast DOT net
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.35
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

Robbo wrote:
>>> I use Free DOS.
>>
>> I have no idea about anything specific to any sort of DOS. However,
>> serial communication in DOS apps *running under Windows* is known to
>> be unreliable. Because of that many years ago I had to change the
>> protocol to account for lost or corrupt data packets.
>
> First of all, thank you all for answers.
>
> I don't use any dos box under Windows. I use pure DOS (but it is Free
> DOS, not MS DOS).
>
>>> One more thing: I installed special 2xRS232+1xLPT
>>> expansion card in the PC and connected the electronic
>>> device with RS232 to it. I found that problems with
>>> loosing sent commands are more frequently than
>>> when I connected RS232 cable directly to a main board.
>>
>> Btw, do you use BIOS to do the serial I/O or something else? The
>> reason for the question is that BIOS serial I/O is rather limited
>> and might even be buggy and I don't remember any decent terminal
>> application using it. At the same time, if it's all your code, not
>> the BIOS'es, there might be some bug just as well.
>
> I don't use BIOS's serial procedures. I write and read directly
> to/from ports.
> Below, there are my serial procedures. I'll be glade if you could
> find a bit of time
> to review them and check they are correct. Thanks in advance.
> I don't use interrupts.
> I use presented functions to send and receive short (2 characters
> long, sometimes
> 7 characters long) commands with '\0' at the end of each.
>
>
> enum {
>    RECVBUF_MAX = 32,                    /* max. size of receiving
> buffer */
>    RECVBUF_USER_MAX = RECVBUF_MAX + 2,
> };
>
> unsigned int COM = 0x3f8;                /* COM do interfejsu */
> unsigned long uartSpeed = 57600;         /* szybkosc transmisji */
>
> /* initUART: initialization
> */
> void initUART(unsigned int com)
> {
>    outportb(com + 1, 0);                        /* interrupts off */
>    outportb(com + 3, 0x80 | inportb(com + 3));  /* UART programming
>    mode */ outportb(com, (115200 / uartSpeed) & 0xff);  /* 57600 bps
>    */ outportb(com + 1, (115200 / uartSpeed) >> 8);
>    outportb(com + 3, 0x03);                     /* 8-bit, no parity */
>    outportb(com + 3, 0x7f & inportb(com + 3));
>    outportb(com + 2, 0xc7 | inportb(com + 2));  /* enable FIFO FCR */
>    outportb(com + 4, 0x0);
> }

I know some UART chips behave weirdly if the order of register 
initialization is different from something more or less standard.

Here's what I do (excerpt from some asm code of mine):
PortSettings:
; configure ports for 115200, 8 bits/word, 1 stop bit, no parity, no break
;       db      reg index, and mask, or mask
        db      MCR, 0x00, 0x00 ; DTR = 0, RTS = 0, loop = 0
        db      LCR, 0x7F, 0x00 ; DLAB = 0
        db      IER, 0x00, 0x00 ; IER = 0 -- disable UART interrupts
        db      FCR, 0x00, 0x00 ; FCR = 0 -- disable/clear FIFOs
        db      LCR, 0xFF, 0x80 ; DLAB = 1
        db      DLL, 0x00, 0x01 ; DLL
        db      DLM, 0x00, 0x00 ; DLM
        db      LCR, 0x00, 0x03 ; DLAB = 0, 8 bits/word, 1 stop bit, no 
parity, no break
        db      FCR, 0x00, 0x00 ; FCR = 0 -- disable/clear FIFOs
        db      MCR, 0x00, 0x03 ; DTR = 1, RTS = 1, loop = 0
so using the above table I read UART registers one by one as indicated in 
the table, apply the and mask then the or mask and then write the value back 
to the register. This used to work for me.

> char recvBuf[RECVBUF_USER_MAX] = "\0";
> char *recvBufPtr = recvBuf;
>
> /* recvTxt: check if there is data in receiving buffer and if so,
> copy them to "s"
> */
> int recvTxt(char *s)
> {
>    int p;
>    unsigned char c;
>    char tt[32];
>
>    /* receiving data which eventually was sent to us */
>    while ((inportb(COM + 5)) & 0x01) {
>        c = inportb(COM);
>
>        if (recvBufPtr - recvBuf < RECVBUF_MAX)
>            *recvBufPtr++ = c;

Can you make sure you don't lose any characters in here? Add a breakpoint or 
a counter for the opposite condition of this if.

>    }
>
>    /* if buffer is empty, return 0 */
>    if ((recvBufPtr == recvBuf) || (*(recvBufPtr - 1) != '\0'))
>        return 0;

Also, if the input doesn't contain a 0 byte (due to a bug or I/O error) and 
fills up recvBuf, you're stuck and the code below won't be executed. Btw, 
it's a good idea to know when a command byte sequence begins, that is, it 
should also have some special byte in the beginning (not onlt at the end) so 
that it's possible to resynchronize if something goes wrong.

>    strncpy(s, recvBuf, p = (recvBufPtr - recvBuf));
>    s[p] = '\0';

Double zero terminated? :)

>    if (debug == 1) {
>        char t[128];
>
>        sprintf(t, "recv.: \"%s\"", s);
>        newState(t);
>    }
>
>    recvBufPtr = recvBuf;
>
>    return p;
> }
>
>
> /* sendTxt: sends text via UART
> */
> void sendTxt(const char *s)
> {
>    char flagTrans = 0;
>
>    if (debug == 1) {
>        char t[128];
>
>        sprintf(t, "sent: \"%s\"", s);
>        newState(t);
>    }
>
>    delay(50);
>
>    /* waiting for completion of sending previously sent chain of
> characters */
>    while (!(inportb(COM + 5) & 0x20))
>        ;
>
>    if ((s == NULL) || (s[0] == '\0'))
>        return;
>
>    /* sending */
>    while (flagTrans == 0) {
>
>        if (*s == '\0')
>            flagTrans = 1;
>
>        /* waiting for completion of sending of previous character */
>        while (!(inportb(COM + 5) & 0x20))
>            ;
>
>        outportb(COM, (unsigned char)*s++);
>    }
> }

I don't see anything particularly bad. Try a full UART register 
initialization as in the above table.

Alex
P.S. my old serial chat program with somewhat simpler UART initialization:
///////////////////////////////////////////////////////
// Serial Chat program by Alexei A. Frounze (c) 2000 //
//                                                   //
// Compiler: Borland C or DJGPP                      //
//                                                   //
// E-Mail  : alexfru AT chat DOT ru                         //
// Homepage: http://alexfru.chat.ru                  //
// Mirror  : http://members.xoom.com/alexfru         //
///////////////////////////////////////////////////////

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

#ifdef DJGPP
#include <sys/movedata.h>
#endif

// Baud rates //

#define B_110   1040
#define B_150    768
#define B_300    384
#define B_600    192
#define B_1200    96
#define B_2400    48
#define B_4800    24
#define B_9600    12
#define B_19200    6
#define B_38400    3
#define B_57600    2
#define B_115200   1

// Size of character //

#define BITS_5          0
#define BITS_6          1
#define BITS_7          2
#define BITS_8          3

// Number of stop bits //

#define STOPS_1         0
#define STOPS_2         4

// Parity type //

#define PARITY_NO       0
#define PARITY_EVEN     0x18
#define PARITY_ODD      8

// Registers //

#define IO_REG          0
#define LO_DIV          0
#define HI_DIV          1
#define INT_REG         1
#define INT_ID          2
#define CONTROL         3
#define MODEM           4
#define STATUS          5
#define MSTATUS         6

// some extra constants

#define ESC             27
#define CR              13
#define LF              10

// Base addresses of ports //

int base[4]={0,0,0,0};

// Function that finds base addresses of all serial ports //

int find_base_addresses() {
  int res=0, i;
  short addr;

  for (i=0;i<4;i++) {
#ifndef DJGPP
    addr = (short) peek (0x40, i*2);
#else
    _dosmemgetw (0x400+i*2, 1, &addr);
#endif
    base[i] = addr;
    if (addr) res++;
  }

  return res;
}

int OpenCOM (int ComNo, int BaudRate, char Config) {
  int b;

  if ((ComNo<1) || (ComNo>4)) return 0;
  b = base[ComNo-1];
  if (!b) return 0;

  // Waiting while the previous data is being sent...
  while ((inportb(b+STATUS) & 0x60) != 0x60) {};

  // Programming the port
  outportb (b+CONTROL, 0x80);
  outportb (b+HI_DIV, BaudRate >> 8);
  outportb (b+LO_DIV, BaudRate & 0xFF);
  outportb (b+CONTROL, Config);
  outportb (b+MODEM, 0);
  outportb (b+INT_REG, 0);

  return 1;
}

int CloseCOM (int ComNo) {
  int b;

  if ((ComNo<1) || (ComNo>4)) return 0;
  b = base[ComNo-1];
  if (!b) return 0;

  outportb (b+INT_REG, 0);
  outportb (b+MODEM, 0);
  return 1;
}

int SendChar (int ComNo, char value) {
  int b;

  if ((ComNo<1) || (ComNo>4)) return 0;
  b = base[ComNo-1];
  if (!b) return 0;

  // Waiting while previous character is being sent
  while ((inportb(b+STATUS) & 0x20) == 0) {};

  // Sending the character
  outportb (b, value);

  return 1;
}

int ReceiveChar (int ComNo, char *value) {
  int b;

  if ((ComNo<1) || (ComNo>4)) return 0;
  b = base[ComNo-1];
  if (!b) return 0;

  // If there is no any available character, quit with result of 0
  if ((inportb(b+STATUS) & 1) == 0) return 0;

  // otherwise we get the character form the port and return result of 1
  *value = inportb (b);
  return 1;
}

int main() {
  int serial_ports, i;
  int ComNo;
  char c, k;

  clrscr();
  printf ("Serial Chat program by Alexei A. Frounze (c) 2000\n\n");
  printf ("E-Mail  : alexfru AT chat DOT ru\n");
  printf ("Homepage: http://alexfru.chat.ru\n");
  printf ("Mirror  : http://members.xoom.com/alexfru\n\n");
  serial_ports = find_base_addresses();

  printf ("There are %d serial ports available.\n", serial_ports);
  if (!serial_ports) return 0;

  printf ("\nBase addresses are:\n");
  for (i=0;i<4;i++)
    if (base[i])
      printf ("  COM%d ... 0x%X\n", 1+i, base[i]);

  printf ("\nPlease choose COM port number: ");
  ComNo = getch();
  printf ("%c\n", ComNo);

  ComNo -= '0';
  if ((ComNo < 1) || (ComNo > 4)) {
    printf ("Ivalid number.\n");
    return 0;
  };
  if (!base[ComNo-1]) {
    printf ("COM%d doesn't exist.\n", ComNo);
    return 0;
  };

  printf ("You've choosen COM%d\n", ComNo);

  if (!OpenCOM (ComNo, B_9600, BITS_8+STOPS_1+PARITY_NO)) {
    printf ("Couldn't open the port.\n");
    return 0;
  };

  printf ("\nCOM%d port is open. Enjoy the chat. Hit ESC for quit.\n\n", 
ComNo);
  while (ReceiveChar (ComNo, &c)) {};   // skip data from the previos 
session

  do {
    if (ReceiveChar (ComNo, &c)) {      // if there is a character 
available...
      switch (c) {
        case ESC:
          printf ("Remote machine disconnected.\n"); // :))
          break;
        case CR:
          printf ("\n");                // move the cursor to the new line
          break;
        default:
          printf ("%c", c);             // print the received chracter
      }
    }
    if (kbhit()) {
      k = getch();
      if (!SendChar (ComNo, k)) {
        printf ("Couldn't send a character.\n");
        return 0;
      };
    } else k=0xFF;
  } while (k!=ESC);                     // quit (disconnect :)

  CloseCOM (ComNo);
  return 0;
}

P.P.S. how's the other PC that you wanted to try out?

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019