I've got a few programmes written in Java to talk to devices like the SHT21 temperature/humidity sensor. All were rather easy to develop with the Java RXTX library. I am hoping to convert them to C is it's more universally available than Java. However I just can't seem to get the most simple thing working properly with the Linux terminal IO API. I've reduced my problem down to a simple test program to write a CR (return key) and look for the "HiZ>" prompt in response. I can get this to work on rare occasions (about 1 time in 5) if I close the serial port and immediately reopen after writing the CR character. However if I use tcdrain() which is supposed to ensure that the write buffer is written to the wire, it does not work.
To compile using tcdrain():
gcc -DUSE_TCDRAIN -o test_bp test_bp.c
To compile using close/reopen instead of tcdrain():
gcc -DCLOSE_AND_REOPEN -o test_bp test_bp.c
To run:
./test_bp /dev/ttyUSBx
(substitute x with whatever the BusPirate device is).
I wonder could any expert in the Linux teminal IO API cast their eye over this code and tell me what I'm doing wrong.
Thanks very much,
Joe.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
#include <sys/fcntl.h>
/**
* This is a unix/Linux serial port test to write
* a CR (return key) to a BusPirate in normal
* command mode and wait for the "HiZ>" prompt
* in reponse to the CR.
* It does not work. It seems the CR is only
* written when the port is closed. tcdrain()
* does not appear to be working. I can make
* it work by closeing the port after writing
* the CR and quickly reopening it. In most cases
* I loose the first few characters of "HiZ>"
* but about 1 time in 5 I can catch them all.
* Using tcdrain() never works.
*/
void usage (char *exeName) {
fprintf (stderr,"%s tty-devicen",exeName);
}
int main (int argc, char **argv) {
int fd,i,c,v,n;
uint8_t buf[4];
if (argc < 2) {
usage(argv[0]);
exit(-1);
}
char *deviceName = argv[1];
fprintf (stderr,"Opening device %sn", argv[1]);
/* open device file */
fd = open(deviceName,O_RDWR);
if (fd==0) {
fprintf (stderr,"error opening device %sn",deviceName);
return EXIT_FAILURE;
}
struct termios tios;
int status=tcgetattr(fd,&tios);
if (status < 0) {
fprintf (stderr,"error calling tcgetattrn");
return -1;
}
// Set tx/rx speed at 115200bps, and set raw mode
cfsetispeed(&tios,B115200);
cfsetospeed(&tios,B115200);
cfmakeraw(&tios);
fprintf (stderr,"sending CRn");
buf[0] = 0x0D;
write(fd,buf,1);
#ifdef USE_TCDRAIN
// tcdrain() is supposed to ensure that anything written has been
// sent on the wire.
tcdrain(fd);
#endif
#ifdef CLOSE_AND_REOPEN
// By closing and immediately reopening the port I can make
// this work about 1 time out of 5.
close(fd);
fd = open(deviceName,O_RDWR);
if (fd==0) {
fprintf (stderr,"error opening device %sn",deviceName);
return EXIT_FAILURE;
}
#endif
// Wait for prompt HiZ>
// 'H' = 0x48, 'i' = 0x69, 'Z' = 0x5A, '>' = 0x3E
v=0; i=8;
while ( (v != 0x48695A3E) && (--i != 0) ) {
n = read(fd,buf,1);
// timeout
if (n==0) {
fprintf(stderr,"T ");
continue;
}
// error
if (n<0) {
fprintf(stderr,"E ");
continue;
}
c = buf[0];
fprintf (stderr,"i=%d fd=%d n=%d c=%x v=%xn",i,fd,n,c,v); fflush(stderr);
v <<= 8;
v |= c;
}
if (i == 0) {
fprintf (stderr,"Fail!n");
return EXIT_FAILURE;
}
fprintf (stderr,"Success!n");
return EXIT_SUCCESS;
}