On 23 Sep 2004 09:22:39 -0700
plinda77@yahoo.com (linda) wrote:
> #define ENQ 5
> #define ACK 6
> #define NAK 15
> #define STX 2
> #define ETX 3
>
> #define QUERY "XX" /* XX, something to represent an query, say 2
> bytes */
>
> int main()
> {
> int fd;
> int io_status;
> int write_status;
> int close_status;
> struct termio t;
Don't use termio, it has been superseded by termios.
> char *device = "/dev/devicefile";
> char query[10];
> char recvbuf[10];
>
> sprintf(query, "%c%s%c\n", STX, QUERY, ETX);
Always use snprintf, it avoids buffer overflows.
> /* need to encapsulate QUERY between the STX and ETX, to be recognize
> by the robot */
>
> if((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY))==-1)
> fprintf(stderr, "Open RS232 Fail%d!\n", fd);
>
> if((io_status = ioctl(fd, TCGETA, &t))==-1)
> fprintf(stderr, "IOCTL TCGETA Fail!\n");
Use tcgetattr() and tcsetattr().
>
> t.c_cflag=B9600|CS8|HUPCL|CREAD;
>
> if((io_status = ioctl(fd, TCSETA, &t))==-1)
> fprintf(stderr, "IOCTL TCSETA Fail!%d\n", io_status);
You could try to print errno (it's helpful :-).
> if((write_status = write(fd, &query, 5))==-1)
> fprintf(stderr, "Write RS232 Fail!%d\n", write_status);
You should output the bytes in a loop, and check for
the number of bytes written.
> /* let say the query returns 2 bytes, YY */
> /* actual data return from robot and received will be "2YY3" but ascii
> character 2 and 3 is not printable(is this the problem?) therefore it
> will be YY, as STX, "YY", ETX */
>
> if((read_status = read(fd, &recvbuf, 5))==-1)
> fprintf(stderr, "read RS232 Fail!%d\n", read_status);
This is not the way to go about it. You should switch to
raw mode, and read character by character.
Once you've got your tty in raw mode, with the proper number
of characters and timer set, you can start reading the characters.
You'll need to know the robot's protocol to make reasonable
vmin/vtime settings.
> /* read_status received but is 0*/
>
> close(fd);
>
> }
> /* End of code */
>
> Is there any settings that are capable of filter away the STX and ETX
> during read? or it that needed?
Here's something I hacked up. Warning: it's not tested as I
don't currently have a serial device to hang off a HP-UX serial
port. It should more or less work - I hope (famous last words).
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <strings.h>
#include <termios.h>
#include <sys/fcntl.h>
#define ENQ 5
#define ACK 6
#define NAK 15
#define STX 2
#define ETX 3
#define QUERY "XX" /* XX, something to represent an query, say 2 bytes */
/* Prototypes */
void fatal(char *);
int tty_raw(int, int, int);
char *device = "/dev/tty0p0";
int main(int argc, char *argv[]) {
int bcount; /* byte counter */
int osize; /* output size */
int fd;
char query[10];
char recvbuf[10];
switch (argc) {
case 0:
case 1:
break;
case 2:
device = argv[1];
break;
default:
fprintf(stderr, "Format: %s: { tty-device (default: %s) }\n",
argv[0], device);
exit(1);
break;
}
/* Open the tty and put in raw mode */
if((fd = open(device, O_RDWR | O_NOCTTY))==-1) {
fatal("Open RS232 Failed");
}
if (!isatty(fd)) {
fatal("Not a tty");
}
if (tty_raw(fd, 0, 10) < 0) { /* one character, 10 secs timeout */
fatal("Cannot set to raw mode");
}
/* Prepare the output query */
osize = snprintf(query, sizeof(query), "%c%s%c\n", STX, QUERY, ETX);
/* Send the message down the tty */
bcount = 0;
while (bcount < osize) {
int w;
if ((w = write(fd, &query[bcount], osize-bcount)) == EOF) {
break;
}
if (w == -1 && errno == EAGAIN) {
continue; /* no data available in non-blocking mode */
}
bcount += w;
}
/* Read the reply from the robot */
bcount = 0;
while (bcount < sizeof(recvbuf)) { /* Stop buffer overflow */
int r;
if ((r = read(fd, &recvbuf[bcount], 1)) == 0) {
fatal("Robot closed connection");
}
if (r == -1 && errno == EAGAIN) {
continue; /* no data available in non-blocking mode */
}
if (bcount == 0 && recvbuf[bcount] != STX) {
fatal("Robot lost its mind");
}
if (recvbuf[bcount] == ETX) {
break;
}
bcount += r;
}
/* Do something with the reply */
recvbuf[bcount] = '\0'; /* Make it printable */
/* skip STX */
fprintf(stdout, "Reply from robot was: <%s>\n", recvbuf+1);
exit(0);
}
/* Switch terminal to raw mode */
int tty_raw(int tty_fd, int vmin, int vtime) {
struct termios cooked;
struct termios raw;
/* Keep a copy so we can go back in case of error */
tcgetattr(tty_fd, &cooked);
tcgetattr(tty_fd, &raw);
/* Set flags */
raw.c_lflag = 0; /* local flags */
/* Alternatively, remove the following flags:
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); */
raw.c_iflag = 0; /* input flags */
/* Alternatively, remove the following flags:
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); */
raw.c_oflag = 0; /* output flags */
/* Alternatively, remove the following flag:
raw.c_oflag &= ~(OPOST); */
raw.c_cflag |= (B9600|CS8); /* control flags - make sure we get 8bits
*/
/* control characters: remove special treatments */
raw.c_cc[VINTR] = '\0';
raw.c_cc[VQUIT] = '\0';
raw.c_cc[VERASE] = '\0';
raw.c_cc[VKILL] = '\0';
raw.c_cc[VSTART] = '\0'; raw.c_cc[VSTOP] = '\0';
/* control characters: minimum number of bytes, timer before return*/
/* eg vmin = 5, vtime = 5 means return after 5 bytes or half a second
after the first byte */
raw.c_cc[VMIN] = vmin;
raw.c_cc[VTIME]= vtime;
/* Now put the tty in raw mode after flushing */
if (tcsetattr(tty_fd, TCSAFLUSH, &raw) < 0) {
tcsetattr(tty_fd, TCSAFLUSH, &cooked);
return -1;
}
return 0;
}
/* Get out on fatal errors */
void fatal(char *message) {
if (errno) {
fprintf(stderr, "%s: %s\n", message, strerror(errno));
} else {
fprintf(stderr, "%s\n", message);
}
exit (1);
}
It compiles OK with gcc -Wall on HP-UX 11.0, the rest is up to you
(watch out for possible broken lines when copy/pasting the code).
Take care,
--
Stefaan
--
"What is stated clearly conceives easily." -- Inspired sales droid