I have written a couple of bash script files that communicate via two serial ports. One script can be thought of as a receiver and the other as a transmitter. The receiving script reads and displays data line by line until it reads the character sequence <break>
. It then stops listening, and sends a character sequence of either one
or two
back to the transmitter. The script is thus:
#!/bin/bash
# Read and reply bash script.
exec 3<> /dev/ttyS4
while true; do
#cat -v /dev/ttyS4 | while read -r input; do
while read -r -u 3 input; do
if [ "$input" = "<break>" ]
then
echo "break command received."
break
else
echo -e "${input}"
fi
done
echo "Sending selection"
if [ "$selection" = "one" ]
then
selection="two"
else
selection="one"
fi
echo "$selection" >&3
done
The transmitter script transmits some character data and then waits for the reply of one
or two
from the receiver script above:
exec 4<> /dev/ttyS0
selection="one"
while true; do
echo "************************************" > /dev/ttyS0
echo " Selection: ${selection}" > /dev/ttyS0
echo "************************************" > /dev/ttyS0
echo "<break>" > /dev/ttyS0
read -r -t 3 -u 4 input
if [ -z "$input" ]
then
echo "Response from remote timed out."
elif [ "$input" = "one" ]
then
selection=$input
elif [ "$input" = "two" ]
then
selection=$input
colour=$RED
else
echo "Unknown selection: $input"
fi
sleep 1
done
The above two scripts work fine and the receiver script correctly identifies the <break>
character sequence.
I wish to replace the 'transmitter' script with a small C program however I find that when I send the character sequence <break>
the receiver script this time does NOT identify is as the 'end-of-transmission', is simple echos <break>
to stdout, and NOT break command received
. I have tried several things such as adding escape characters but there is obviously something different about the way Bash echo
works and how I send the data in my C code:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
int main(int argc, char *argv[]) {
int selected_tool = DEFAULT_TOOL_SELECTION;
FILE *ser2_fd_write, *ser2_fdrw;
struct termios tios, tios_w; // ser 2 termios structure
int ser2_fd, ser2_fdw;
char read_buffer[BUFFER_SIZE];
struct timespec tdelay;
bzero(&tdelay, sizeof(tdelay));
tdelay.tv_sec = 1;
tdelay.tv_nsec = 5000;
if ((ser2_fd = open("/dev/ttyS0", O_RDWR)) == -1){
printf("Unable to open ttyS0 as read-write only.\n");
return EXIT_FAILURE;
}
bzero(&tios, sizeof(tios));
cfsetispeed(&tios, B38400);
cfsetospeed(&tios, B38400);
tios.c_cflag = B38400 | CS8 | CLOCAL | CREAD | CRTSCTS;
tios.c_iflag = IGNPAR;
tios.c_oflag = 0;
tios.c_lflag = ICANON; //0
tios.c_cc[VTIME] = 0;
tios.c_cc[VMIN] = 10;
tcflush(ser2_fd, TCIFLUSH);
if (tcsetattr(ser2_fd, TCSANOW, &tios) == -1){
printf("Could not set ser 2 attributes.\n");
return -1;
}
if ((ser2_fdrw = fdopen(ser2_fd, "awr")) == NULL){
printf("Unable to open file descriptor.\n");
return EXIT_FAILURE;
}
while(1){
push_to_ser2(ser2_fdrw, selected_tool);
/*
* This is where sending <break> differs from echo
*/
//fputs("break", ser2_fdrw);
fprintf(ser2_fdrw, "break\r\n");
//fprintf(ser2_fdrw, "\r\n");
//write(ser2_fd,"break\r\n", 9);
fflush(ser2_fdrw);
int c = 0;
nanosleep(&tdelay, NULL);
tcflush(ser2_fd, TCIOFLUSH);
tcdrain(ser2_fd);
fcntl(ser2_fd, F_SETFL, 0);
if ( (c = read(ser2_fd, read_buffer, BUFFER_SIZE)) > 0){
read_buffer[c] = 0;
if (strcmp(read_buffer, "one\r\n") == 0){
selected_tool = 1;
} else if (strcmp(read_buffer, "two\r\n") == 0){
selected_tool = 2;
}
}else{
}
}
return EXIT_SUCCESS;
}
/*
* Convenience function to push data to ser 2
* *c_data pointer to the card data
* *t_data pointer to the tool data
*/
void push_to_ser2(FILE * fd, int tool){
fprintf(fd, "**********************************************************\n");
fprintf(fd, "* *\n");
fprintf(fd, "* Tool %d Data *\n", tool);
fprintf(fd, "* *\n");
fprintf(fd, "**********************************************************\n");
fprintf(fd,"\r\n");
fflush(fd);
}
I've tried various alterations to the termios
struct too but it makes no difference. Any ideas?
There are several issues with your code that should be corrected:
bzero(&tios, sizeof(tios))
the code should be calling tcgetattr() to properly initialize the structure. This can be a serious issue for canonical input, as the existing code will have zeroed out all of the control code specifications instead of having proper definitions.read(ser2_fd,...)
is silently ignoring errors.