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" Newsgroups: comp.os.msdos.djgpp References: Subject: Re: RS232 transmission sometimes fail on AM2 Date: Sun, 22 Jul 2007 01:26:05 -0700 MIME-Version: 1.0 Content-Type: text/plain; format=flowed; charset="koi8-r"; reply-type=original Content-Transfer-Encoding: 7bit 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: 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 #include #include #include #ifdef DJGPP #include #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?