(Edited 2/1/14 - Paired down code to be specific to this issue. Tested with smaller code. Edited this pose to show entire new code which still has the same issue.)
I'm working on a beagle bone black in the Angstrom Linux distribution kernel 3.8 using the POSIX serial guide.
I have a set of functions to handle serial communication defined in serial.c I want to use these as a library for other programs to use. I am declaring many of the common variables for these functions as static at the top of serial.c before the function definitions. My intent with this is that these will be like global variables but just for the functions in serial.c and also that they will keep their value between function calls. It does appear as if this working as I intended.
One of the functions is send_serial(). It does just what it says, sends data to the serial port. If I write a main() function inside of serial.c then and call it from inside the same file it is defined then send_serial() works as expected. As soon as the program hits the line with send_serial(), data is written to the serial port immediately. I can see the send and receive lights flash and I get back the expected data.
However when I try to use send_serial() from a different file it behaves oddly. It executes ok and it returns the correct number of bytes written and the program continues to the next line, except there is no actual serial port communication at all. Not until the program ends or I call close on the serial port, does is the data actually sent out on the serial port.
Why will it work fine from inside the same file, but it works incorrectly from a different file. I'm using the exact same functions to setup and open the serial port in both cases.
serial.h
#ifndef _PUP_SERIAL_ /* Include guard */
#define _PUP_SERIAL_
#define MAXBUF 1024
typedef struct byte_array {
unsigned char byte[MAXBUF];
int count;
} byte_array;
void set_serial_debug(int debug_value);
void close_serial();
int setup_serial_port(char * port_name);
int send_serial(byte_array message);
byte_array read_serial();
byte_array test_message();
#endif
serial.c
//#define _SERIAL_IS_MAIN_ // comment out this line for this file to be a library instead of main function
#include <stdio.h> /* Standard input/output definitions */
#include <fcntl.h> /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/time.h>
#include "serial.h"
static int debug;
static int fd;
static struct termios options;
void print_bytes_as_hex(char * str, byte_array message)
{
int n;
int i;
printf(str);
if (message.count > 0)
for (i = 0; i < message.count; i++)
{
n = (int) message.byte[i];
printf("0x%.2x ", n);
}
else
printf("-x--");
printf("\n");
} // end of print bytes as hex
int setup_serial_port(char * port_name)
{
fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
printf("Opened up port %s as number %d",port_name,fd);
tcgetattr(fd, &options);
if (port_name == "/dev/ttyUSB0")<--Fixed by changing to: if (strcmp(port_name,"/dev/ttyUSB0")==0)
options.c_cflag &= ~CRTSCTS; // set NO RTS control for USB
else
options.c_cflag |= CRTSCTS; // set RTS control for ttyO#
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// set No parity (8N1):
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_iflag |= IGNBRK;
options.c_iflag &= ~(IXON | IXOFF | IXANY); // No software handshake
options.c_lflag = 0;
options.c_oflag = 0;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Raw Input
//options.c_lflag |= (ICANON | ECHO | ECHOE); // Canonical input
options.c_cc[VMIN] = 1; // 1 means read dos not block
options.c_cc[VTIME] = 1; // 1 means 0.1 seconds read timeout
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode
/* Make raw */
cfmakeraw(&options);
/* Flush Port, then applies attributes */
tcflush( fd, TCIFLUSH );
fcntl(fd, F_SETFL, 0);
tcsetattr(fd, TCSANOW, &options); // Set the new options for the port
if (fd == -1)
{ //Could not open the port.
perror("open_port: Unable to open");
printf("Could not open port %s\n",port_name);
}
else // port is open
printf("Port %s is open as # %d\n",port_name, fd);
return fd;
} // End of setup_serial_port
void set_serial_debug(int debug_value)
{
debug = debug_value;
}
void close_serial()
{
close(fd);
}
int send_serial(byte_array message)
{
int n;
printf("about to send to serial port...\n");
n = write(fd, message.byte, message.count);
printf("sent %d bytes to serial port %d\n",n,fd);
return n;
}
byte_array read_serial()
{
static byte_array message;
int n;
int i;
printf("Attempting to read from serial port %d...\n",fd);
for (i = 0; i < 8; i++)
n = read(fd, &message.byte[i], 1);
message.count = i;
printf("read %d bytes from the serial port %d\n",message.count,fd);
return message;
}
byte_array test_message()
{
int i;
unsigned char st[] = {0x02, 0x10, 0x27, 0x0D, 0x02, 0x01, 0xFB, 0x43, 0x56, 0x00, 0x00, 0x00, 0x00, 0xDC};
byte_array return_message;
for (i = 0; i < 14; i++)
return_message.byte[i] = st[i];
return_message.count = 14;
return return_message;
}
#ifdef _SERIAL_IS_MAIN_
int main(int Count, char *Strings[])
{
setup_serial_port("/dev/ttyUSB0");
byte_array out_message = test_message();
byte_array in_message;
print_bytes_as_hex("sending: ",out_message);
send_serial(out_message);
in_message = read_serial();
print_bytes_as_hex("recieved: ",in_message);
}
#endif
main.c
#include <stdio.h>
#include "serial.h"
byte_array in_message;
byte_array out_message;
int main(int Count, char *Strings[])
{
setup_serial_port("/dev/ttyUSB0");
byte_array out_message = test_message();
byte_array in_message;
print_bytes_as_hex("sending: ",out_message);
send_serial(out_message);
in_message = read_serial();
print_bytes_as_hex("recieved: ",in_message);
}
If I call send_serial(message); from inside serial.c it works.
# gcc -o serial serial.c
# ./serial
Opened up port /dev/ttyUSB0 as number 3Port /dev/ttyUSB0 is open as # 3
sending: 0x02 0x10 0x27 0x0d 0x02 0x01 0xfb 0x43 0x56 0x00 0x00 0x00 0x00 0xdc
about to send to serial port...
sent 14 bytes to serial port 3 <-- Send and Receive Lights blink
Attempting to read from serial port 3...
read 8 bytes from the serial port 3
recieved: 0x02 0x10 0x27 0x07 0x81 0x02 0x0e 0xbc
If I call send_serial(message); from outside of serial.c it does not send until the program ends.
(edit serial.c to comment out //#define _SERIAL_IS_MAIN_)
# gcc -o main main.c serial.c
# ./main
Opened up port /dev/ttyUSB0 as number 3Port /dev/ttyUSB0 is open as # 3
sending: 0x02 0x10 0x27 0x0d 0x02 0x01 0xfb 0x43 0x56 0x00 0x00 0x00 0x00 0xdc
about to send to serial port...
sent 14 bytes to serial port 3 <-- comm lights do not blink at all
Attempting to read from serial port 3... <-- Program waits here for ever until CTRL^C
^C <-- Once I press CTRL^C snd and rec comm lights blink
When I run this program from main.c, it waits at the read_serial() function because it is waiting for a reply from my device. The device is not sending back a reply, because my program never sent the message to the serial port. It said it sent it, but it did not. Once I press CTRL^C, the program (or maybe os) sends the message, the device receives the message and it responds back to me. However I never get the message because the program is no longer running.