(E-Mail Removed) (Detlef Jockheck) wrote:
>Hi,
>
>I have a printer that answers with "0x00 0x0d" when I send a
>reset-command. I can see this answer on my monitoring-box but cannot
>read this two bytes with "read" command. What may I have done wrong...
>
>I'm using
We need to see a complete, compilable, snippet of code in order
to really see what is happening; but there are at least a couple
of obvious problems with the fragment shown below. There are
also several potential problems that may or may not really be
causing you trouble.
>--- cut ---
> /*
> Übertragungsparameter: 9600 8 Bit, None Parity, 2 Stoppbits
Why are you using 2 stop bits??? Does the printer really need
that? If not, use only one.
If it really needs just 1 and you set your port to 2, your send
data to the printer will be fine, but on any data received from
the printer that involves more than a few bytes of data you'll
get garble. By the same token, if you set your port to 1 bit
and the printer really does need 2 the opposite will happen, and
the data you send will be garbled while what you receive will be
just fine. (The device set to 1 stop bit can receive data from
the device set to 2 stop bits. The device set to 1 stop bit
cannot send data to the device set to 2 stop bits.)
> BAUDRATE - wird global definiert (s.o.)
> IGNBRK - Break-Signale im Datenstrom ignorieren
> IGNPAR - keine Parität
> CSTOPB - zwei Stop-Bits
> CS8 - 8 Datenbits
> CREAD - Empfang erlauben
> CLOCAL - Modem Steuerleitungen ignorieren
> */
Assuming you have initialized your newtio struct by calling
tcgetattr(fd, &newtio), you want to set *every* member of the
struct. As noted below, you may not want to continue using
canonical input, but if you do you will want to set all of the
newtio.c_cc array values (perhaps to 0, for example!). If
you switch to non-canonical mode, only newtio.c_cc[VMIN] and
newtio.c_cc[VTIME] need to be set.
Another problem can be the line discipline, which is
newtio.c_line. However, it is specific to Linux and does not
appear in the termios struct for other unix systems. Hence if
you want to write portable code, you need to use conditionals,
such as
#ifdef __linux__
/*
* N_TTY and other line disciplines are defined in
* <bits/ioctl-types.h>, which is included by
* <sys/ioctl.h>. It would probably be quite safe
* also to just assume a value of 0 is safe, and use
* that instead of N_TTY, and then there is no need
* to include a header file.
*/
#include <sys/ioctl.h>
newtio.c_line = N_TTY;
#endif
Another possible way to initialize the termios struct is to use
"memset(&newtio, 0, sizeof newtio);". That is not strictly
POSIX compliant, because POSIX says it is undefined behavior
when the struct is not initialized by calling tcgetattr(). It
does, however, result in correct behavior on every platform that
I know of including Linux (but is not guaranteed to do so in the
future).
> newtio.c_iflag = IGNBRK | IGNPAR;
>
> newtio.c_oflag = 0;
Setting the c_oflag to 0 might be a problem. Some printers
cannot be configured to use 0x0A (LF) as a newline (as opposed
to using the CRLF combination), and LF is what unix systems
use. One possible fix is to configure your serial port for
OPOST and ONLCR. There are other ways to do it (filtering the
print files, for example, to convert all newlines to be CRLF)
so this may or may not be interesting for you.
> newtio.c_cflag = CS8 | CSTOPB | CREAD | BAUDRATE | CLOCAL;
Linux does not use BAUDRATE in the c_cflag to set the port
speed. Hence you'll want to remove BAUDRATE from the value for
c_cflag.
Set the port speed using the cfsetospeed() and cfsetispeed()
functions before you call tcsetattr(). These functions actually
set members newtio.c_ospeed and newtio.c_ispeed, but you still
want to use the functions rather than set them directly.
Also CLOCAL means the port will not monitor the DCD control
line, so you might want to remove that too. The result should
be that you cannot open the serial port without the printer
connected.
> newtio.c_lflag = ICANON;
This is almost certainly the specific cause of the problem you've
asked about.
The ICANON flag means all input and output will be line
buffered, which probably works fine for output to the printer,
but means you will not see data from the printer until a newline
is received. That may or may not be reasonable, depending on the
printer. In your case, you've stated that when reset the
printer responds with two bytes, 0x0 and 0xd, and you will
therefore not be able to see those bytes with read() because no
newline is being received.
> /* now clean the modem line and activate the settings for the port
>*/
> tcflush(fd, TCIFLUSH);
> tcsetattr(fd, TCSANOW, &newtio);
>--- cut ---
>
>to configure my serial port. For Reading the answer I use:
>
>--- cut ---
> erg = read(fd, received,2);
>--- cut ---
That leaves too much to the imagination. I can't even begin to
figure out if that should work or not.
There are several print spooling programs available for Linux,
and while I'm assuming you have a good reason not to use one of
them directly (a dedicated printer, for example), but you might
well want to download the source code to a couple of them and
take a look at how they configure a serial port.
Note that the Linux Serial-Programming-HOWTO has some
interesting examples, but they are virtually all seriously
flawed, plus there are some significant differences in the
approach one might take for a serial program talking to a
printer and a program talking to a modem. Hence you need
examples _specifically_ concerned with printers, not modems.
--
Floyd L. Davidson <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)
(E-Mail Removed)