linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* How to use an USB<->serial adapter?
@ 2003-08-21 12:44 Boszormenyi Zoltan
  2003-08-21 17:08 ` Greg KH
  2003-08-21 23:18 ` Daniel Egger
  0 siblings, 2 replies; 8+ messages in thread
From: Boszormenyi Zoltan @ 2003-08-21 12:44 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2162 bytes --]

Hi,

I am experimenting with a Prolific USB<->RS232 adaptor. We have
in-house developments that need serial communication and there
are more and more mainboards that provide only one RS232 connector.
(We would need more in one machine...)
So we decided to try an usb-serial converter. The one we bought
was happily recognized by a RedHat 9 system but I couldn't get
two-way communication over this converter.
The null-modem cable is working both ways, in fact I tested it
with my machine's two real 16550s.
lsmod shows usbserial and pl2303, dmesg shows this:

usb.c: registered new driver serial
usbserial.c: USB Serial support registered for Generic
usbserial.c: USB Serial Driver core v1.4
usbserial.c: USB Serial support registered for PL-2303
usbserial.c: PL-2303 converter detected
usbserial.c: PL-2303 converter now attached to ttyUSB0 \
(or usb/tts/0 for devfs)
pl2303.c: Prolific PL2303 USB to serial adaptor driver v0.9

I use the attached sources (serial.h, [posix|win32]-serial.c)
in my MinGW/Linux dual platform programs for low-level serial
communication. Here are two testprograms that I used.

serialtest2 just listens and waits for incoming bytes.
If it receives one, the answer is the byte it got + 1.
serialtest1 iterates 10 times writing a byte and expecting
the answer.

I tried using /dev/ttyUSB0 and /dev/usb/ttyUSB0 (chmod was needed
to open them by an ordinary user, open(2) and tcsetattr(3)
succeeded. What I found is that I can write to /dev/ttyUSB0
with serialtest1 and serialtest2 successfully reads it from
/dev/ttyS0. But the answer from serialtest2 cannot be read
by serialtest1. If these programs both use a real serial port
(ttyS0 and ttyS1) the communication is successful both ways.

setserial produces an error:

# setserial /dev/ttyUSB0
Cannot get serial info: Invalid argument

And to be sure:

# setserial /dev/ttyUSB1
/dev/ttyUSB1: No such device

as expected.

I have the kernel-smp-2.4.20-19.9 (not the very latest) errata kernel
and all user space errata packages installed/upgraded.

-- 
Best regards,
Zoltán Böszörményi

---------------------
What did Hussein say about his knife?
One in Bush worth two in the hand.


[-- Attachment #2: serial.h --]
[-- Type: text/plain, Size: 712 bytes --]

/*
 * Közös fejléc a Win32/POSIX soros programozáshoz
 */

#include <sys/types.h>

#ifndef NEED_WINDOWS_H
#include <termios.h>
#else
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#endif

extern char *serial_names[];

typedef struct {
#ifdef NEED_WINDOWS_H
	HANDLE		fd;
	DCB		olddcb, newdcb;
	COMMTIMEOUTS	oldto, newto;
	size_t		err;
#else
	int		fd;
	struct termios	oldtio, newtio;
	ssize_t		err;
#endif
} serial_t;

serial_t *serial_open(const char *devname);
void	serial_setup(serial_t *serport);
void	serial_close(serial_t *serport);
void	serial_write(serial_t *serport, const char *buffer, size_t n);
void	serial_read(serial_t *serport, char *buffer, size_t n, int wait);
void	serial_delay(int ms);


[-- Attachment #3: posix-serial.c --]
[-- Type: text/plain, Size: 2313 bytes --]

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "serial.h"

char *serial_names[10] = {
	"",
	"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3",
	"/dev/usb/ttyUSB0", "/dev/usb/ttyUSB1", "/dev/usb/ttyUSB2", "/dev/usb/ttyUSB3",
	NULL };

serial_t *serial_open(const char *devname) {
	serial_t	*serport;

	serport = malloc(sizeof(serial_t));

	serport->fd = open(devname, O_RDWR|O_NOCTTY|O_NONBLOCK /*|O_SYNC*/);
	if (serport->fd < 0) {
		free(serport);
		return NULL;
	}

	return serport;
}

void	serial_setup(serial_t *serport) {
	struct termios	*tio1, *tio2;
	int		ret = 0;

	tio1 = &(serport->oldtio);
	tio2 = &(serport->newtio);

	if (tcgetattr(serport->fd, tio1))
		ret = -1;
	memcpy(tio2, tio1, sizeof(struct termios));
	cfmakeraw(tio2);
	cfsetospeed(tio2, B115200);
	cfsetispeed(tio2, B115200);
#if 0
	tio2->c_cflag |= CRTSCTS;
#endif
	tio2->c_cflag |= CREAD|CLOCAL;
	tcflush(serport->fd, TCIOFLUSH);
	if (tcsetattr(serport->fd, TCSANOW, tio2))
		ret = -1;
#if 0
	tcflow(serport->fd, TCOON); tcflow(serport->fd, TCION);
#endif
	serport->err = ret;
}

void	serial_close(serial_t *serport) {
	tcflush(serport->fd, TCIOFLUSH);
	tcsetattr(serport->fd, TCSANOW, &(serport->oldtio));
	close(serport->fd);
	free(serport);
}

void	serial_write(serial_t *serport, const char *buffer, size_t n) {
	int	i;

	serport->err = write(serport->fd, buffer, n);
	tcdrain(serport->fd);
}

void serial_read(serial_t *serport, char *buffer, size_t n, int wait) {
	int pos = 0;
	int err = 0;
	struct timeval tv;
	fd_set set;

	if (wait) {
		FD_ZERO(&set);
		FD_SET(serport->fd, &set);
		tv.tv_sec = 0;
		tv.tv_usec = 250000;
		serport->err = select(serport->fd+1, &set, NULL, NULL, &tv);
		if (serport->err <= 0)
			return;
	}

	while(n--) {
again:
		if (wait) {
			FD_ZERO(&set);
			FD_SET(serport->fd, &set);
			tv.tv_sec = 0;
			tv.tv_usec = 100000;
			serport->err = select(serport->fd+1, &set, NULL, NULL, &tv);
			if (serport->err <= 0)
				return;
		}
		serport->err = read(serport->fd, &buffer[pos++], 1);
		if (serport->err == 0)
			goto again;
		if (serport->err == -1)
			break;
	}
	if (serport->err != -1)
		serport->err = pos;
}

void	serial_delay(int ms) {
	usleep(ms*1000);
}


[-- Attachment #4: win32-serial.c --]
[-- Type: text/plain, Size: 4547 bytes --]

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>

#include <malloc.h>
#include <gdk/gdkwin32.h>
#include <gtk/gtk.h>

#include "serial.h"

char *serial_names[10] = {
	"",
	"COM1:", "COM2:", "COM3:", "COM4:",
	"COM5:", "COM6:", "COM7:", "COM8:",
	NULL };

extern GtkWidget *foablak;

serial_t *serial_open(const char *devname) {
	serial_t *serport;
	HANDLE	fd;
	DWORD	dwError;

	serport = malloc(sizeof(serial_t));

	serport->fd = CreateFile(devname, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
		FILE_FLAG_WRITE_THROUGH, NULL);
	dwError = GetLastError();
	if (dwError == ERROR_FILE_NOT_FOUND) {
		free(serport);
		return NULL;
	}
	return serport;
}

void	serial_setup(serial_t *serport) {
	DCB		*dcb1, *dcb2;
	COMMTIMEOUTS	*to1, *to2;
	DWORD		dwError;

	to1 = &(serport->oldto);
	to2 = &(serport->newto);

	/* Initialize the DCBlength member. */
	dcb1 = &(serport->olddcb);
	dcb2 = &(serport->newdcb);

	serport->olddcb.DCBlength = sizeof (DCB); 

	/* Get the default port setting information. */
	GetCommState(serport->fd, dcb1);
	memcpy(dcb2, dcb1, sizeof(DCB));

	/* Change the DCB structure settings. */
	dcb2->BaudRate = 115200;            /* Current baud */
	dcb2->fBinary = TRUE;               /* Binary mode; no EOF check */
	dcb2->fParity = TRUE;               /* Enable parity checking */
	dcb2->fOutxCtsFlow = FALSE;         /* No CTS output flow control */
	dcb2->fOutxDsrFlow = FALSE;         /* No DSR output flow control */
	dcb2->fDtrControl = DTR_CONTROL_DISABLE /* DTR_CONTROL_ENABLE */;
	                                      /* DTR flow control type */
	dcb2->fDsrSensitivity = FALSE;      /* DSR sensitivity */
	dcb2->fTXContinueOnXoff = TRUE;     /* XOFF continues Tx */
	dcb2->fOutX = FALSE;                /* No XON/XOFF out flow control */ 
	dcb2->fInX = FALSE;                 /* No XON/XOFF in flow control */
	dcb2->fErrorChar = FALSE;           /* Disable error replacement */
	dcb2->fNull = FALSE;                /* Disable null stripping */
	dcb2->fRtsControl = RTS_CONTROL_ENABLE;
	                                      /* RTS flow control */
	dcb2->fAbortOnError = FALSE;        /* Do not abort reads/writes error */
	dcb2->ByteSize = 8;                 /* Number of bits/byte, 4-8 */
	dcb2->Parity = NOPARITY;            /* 0-4=no,odd,even,mark,space */ 
	dcb2->StopBits = ONESTOPBIT;        /* 0,1,2 = 1, 1.5, 2 */

	/* Configure the port according to the specifications of the DCB structure. */
	if (!SetCommState (serport->fd, dcb2)) {
		/* Could not configure the serial port. */
		serport->err = -1;
		return;
	}

	/* Retrieve the time-out parameters for all read and write operations
	   on the port. */
	to1 = &(serport->oldto);
	to2 = &(serport->newto);

	GetCommTimeouts (serport->fd, to1);
	memcpy(to2, to1, sizeof(COMMTIMEOUTS));

	/* Change the COMMTIMEOUTS structure settings. */
	to2->ReadIntervalTimeout = 250;
	to2->ReadTotalTimeoutMultiplier = 0;
	to2->ReadTotalTimeoutConstant = 250;
	to2->WriteTotalTimeoutMultiplier = 0;
	to2->WriteTotalTimeoutConstant = 0;

	/* Set the time-out parameters for all read and write operations
	   on the port. */
	if (!SetCommTimeouts (serport->fd, to2))
	{
		/* Could not set the time-out parameters. */
		serport->err = -1;
		return;
	}
}

void serial_close(serial_t *serport) {
	SetCommState (serport->fd, &(serport->olddcb));
	SetCommTimeouts (serport->fd, &(serport->oldto));
	CloseHandle(serport->fd);
	free(serport);
}

void serial_write(serial_t *serport, const char *buffer, size_t n) {
	DWORD	dwNumBytesWritten;
	int	i;

	serport->err = 0;
	for (i = 0; i < n; i++) {
		WriteFile (serport->fd,	/* Port handle */
			&buffer[i],	/* Pointer to the data to write */
			1,		/* Number of bytes to write */
			&dwNumBytesWritten,/* Pointer to the number of bytes written */
			NULL);		/* Must be NULL for Windows CE */
		serport->err += dwNumBytesWritten;
	}
	if (serport->err != n)
		serport->err = -1;
}

void serial_read(serial_t *serport, char *buffer, size_t n, int wait) {
	DWORD dwBytesTransferred;
	int	i;

	serport->err = 0;
	for (i = 0; i < n; i++) {
		ReadFile (serport->fd,	/* Port handle */
          	&buffer[i],		/* Pointer to data to read */
		1,			/* Number of bytes to read */
		&dwBytesTransferred,	/* Pointer to number of bytes read */
		NULL);			/* Must be NULL for Windows CE */
		serport->err += dwBytesTransferred;
		if (!dwBytesTransferred) {
			serport->err = -1;
			break;
		}
	}
	if (serport->err != n)
		serport->err = -1;
}

void	serial_delay(int ms) {
	Sleep(ms);
}


[-- Attachment #5: serialtest1.c --]
[-- Type: text/plain, Size: 677 bytes --]

/*
 *  serialtest1
 */

#include <stdio.h>
#include "serial.h"

serial_t	*sp;
unsigned char	c1, c2;
int		i;

int main(int argc, char **argv) {
	if (argc != 2)	{
		printf("give device name\n");
		return 1;
	}

	sp = serial_open(argv[1]);
	if (!sp) {
		printf("cannot open %s\n", argv[1]);
		return 1;
	}

	serial_setup(sp);
	if (sp->err < 0) {
		printf("cannot setup %s\n", argv[1]);
	}

	for (i = 0; i < 10; i++) {
		c1 = i;

		serial_write(sp, &c1, 1);

		serial_delay(20);

		serial_read(sp, &c2, 1, 1);

		if (sp->err <= 0)
		printf("written: 0x%02x, couldn't read\n", c1);
			else
		printf("written: 0x%02x, read: 0x%02x\n", c1, c2);
	}

	serial_close(sp);

	return 0;
}



[-- Attachment #6: serialtest2.c --]
[-- Type: text/plain, Size: 668 bytes --]

/*
 *  serialtest2
 */

#include <stdio.h>
#include <stdlib.h>
#include "serial.h"

serial_t	*sp;
unsigned char	c1, c2;
int		i;

void myexit(void) {
	serial_close(sp);
}

int main(int argc, char **argv) {
	if (argc != 2) {
		printf("give device name\n");
		return 1;
	}

	sp = serial_open(argv[1]);
	if (!sp) {
		printf("cannot open %s\n", argv[1]);
		return 1;
	}

	serial_setup(sp);
	if (sp->err < 0) {
		printf("cannot setup %s\n", argv[1]);
	}

	atexit(myexit);

	while (1) {
again:
		serial_read(sp, &c1, 1, 1);
		if (sp->err <= 0)
			goto again;

		c2 = c1+1;

		serial_write(sp, &c2, 1);
		printf("read: 0x%02x, written: 0x%02x\n", c1, c2);

	}

	return 0;
}



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2003-08-27  9:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-21 12:44 How to use an USB<->serial adapter? Boszormenyi Zoltan
2003-08-21 17:08 ` Greg KH
2003-08-22  7:02   ` Boszormenyi Zoltan
2003-08-22 12:05   ` Boszormenyi Zoltan
2003-08-21 23:18 ` Daniel Egger
2003-08-25  6:24   ` Boszormenyi Zoltan
2003-08-25 10:19     ` Daniel Egger
2003-08-27  9:33       ` Boszormenyi Zoltan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).